wined3d: Get rid of IWineD3DTexture.
[wine/wine-gecko.git] / dlls / wined3d / device.c
blobe8bcf9eacc9e6d693938695d85318f2c395f3e45
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 IWineD3DBaseTextureImpl *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->baseTexture.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, IWineD3DBaseTexture **texture)
1106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1107 IWineD3DTextureImpl *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 = (IWineD3DBaseTexture *)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, IWineD3DBaseTexture **ppVolumeTexture)
1142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1143 IWineD3DBaseTextureImpl *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 *ppVolumeTexture = 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 *ppVolumeTexture = NULL;
1163 return hr;
1166 TRACE("(%p) : Created volume texture %p.\n", This, object);
1167 *ppVolumeTexture = (IWineD3DBaseTexture *)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, IWineD3DCubeTexture **ppCubeTexture)
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1210 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1211 HRESULT hr;
1213 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1214 if (!object)
1216 ERR("Out of memory\n");
1217 *ppCubeTexture = 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 *ppCubeTexture = NULL;
1227 return hr;
1230 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1231 *ppCubeTexture = (IWineD3DCubeTexture *)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 /*****
4453 * Get / Set Texture
4454 *****/
4455 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4456 DWORD stage, IWineD3DBaseTexture *texture)
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4460 IWineD3DBaseTexture *prev;
4462 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4464 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4465 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4467 /* Windows accepts overflowing this array... we do not. */
4468 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4470 WARN("Ignoring invalid stage %u.\n", stage);
4471 return WINED3D_OK;
4474 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4475 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4477 WARN("Rejecting attempt to set scratch texture.\n");
4478 return WINED3DERR_INVALIDCALL;
4481 This->updateStateBlock->changed.textures |= 1 << stage;
4483 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4484 TRACE("Previous texture %p.\n", prev);
4486 if (texture == prev)
4488 TRACE("App is setting the same texture again, nothing to do.\n");
4489 return WINED3D_OK;
4492 TRACE("Setting new texture to %p.\n", texture);
4493 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4495 if (This->isRecordingState)
4497 TRACE("Recording... not performing anything\n");
4499 if (texture) IWineD3DBaseTexture_AddRef(texture);
4500 if (prev) IWineD3DBaseTexture_Release(prev);
4502 return WINED3D_OK;
4505 if (texture)
4507 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4508 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4509 GLenum dimensions = t->baseTexture.target;
4511 IWineD3DBaseTexture_AddRef(texture);
4513 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4516 if (!prev && stage < gl_info->limits.texture_stages)
4518 /* The source arguments for color and alpha ops have different
4519 * meanings when a NULL texture is bound, so the COLOROP and
4520 * ALPHAOP have to be dirtified. */
4521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4525 if (bind_count == 1) t->baseTexture.sampler = stage;
4528 if (prev)
4530 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4531 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4533 IWineD3DBaseTexture_Release(prev);
4535 if (!texture && stage < gl_info->limits.texture_stages)
4537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4541 if (bind_count && t->baseTexture.sampler == stage)
4543 unsigned int i;
4545 /* Search for other stages the texture is bound to. Shouldn't
4546 * happen if applications bind textures to a single stage only. */
4547 TRACE("Searching for other stages the texture is bound to.\n");
4548 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4550 if (This->updateStateBlock->state.textures[i] == t)
4552 TRACE("Texture is also bound to stage %u.\n", i);
4553 t->baseTexture.sampler = i;
4554 break;
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4562 return WINED3D_OK;
4565 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4570 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4571 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4574 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4576 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4577 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4580 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4581 if (*ppTexture)
4582 IWineD3DBaseTexture_AddRef(*ppTexture);
4584 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4586 return WINED3D_OK;
4589 /*****
4590 * Get Back Buffer
4591 *****/
4592 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4593 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4595 IWineD3DSwapChain *swapchain;
4596 HRESULT hr;
4598 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4599 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4601 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4602 if (FAILED(hr))
4604 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4605 return hr;
4608 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4609 IWineD3DSwapChain_Release(swapchain);
4610 if (FAILED(hr))
4612 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4613 return hr;
4616 return WINED3D_OK;
4619 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4621 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4623 TRACE("iface %p, caps %p.\n", iface, caps);
4625 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4628 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 IWineD3DSwapChain *swapChain;
4631 HRESULT hr;
4633 if(iSwapChain > 0) {
4634 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4635 if (hr == WINED3D_OK) {
4636 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4637 IWineD3DSwapChain_Release(swapChain);
4638 } else {
4639 FIXME("(%p) Error getting display mode\n", This);
4641 } else {
4642 /* Don't read the real display mode,
4643 but return the stored mode instead. X11 can't change the color
4644 depth, and some apps are pretty angry if they SetDisplayMode from
4645 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4647 Also don't relay to the swapchain because with ddraw it's possible
4648 that there isn't a swapchain at all */
4649 pMode->Width = This->ddraw_width;
4650 pMode->Height = This->ddraw_height;
4651 pMode->Format = This->ddraw_format;
4652 pMode->RefreshRate = 0;
4653 hr = WINED3D_OK;
4656 return hr;
4659 /*****
4660 * Stateblock related functions
4661 *****/
4663 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 struct wined3d_stateblock *stateblock;
4667 HRESULT hr;
4669 TRACE("(%p)\n", This);
4671 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4673 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4674 if (FAILED(hr)) return hr;
4676 wined3d_stateblock_decref(This->updateStateBlock);
4677 This->updateStateBlock = stateblock;
4678 This->isRecordingState = TRUE;
4680 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4682 return WINED3D_OK;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4686 struct wined3d_stateblock **stateblock)
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4689 struct wined3d_stateblock *object = This->updateStateBlock;
4691 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4693 if (!This->isRecordingState) {
4694 WARN("(%p) not recording! returning error\n", This);
4695 *stateblock = NULL;
4696 return WINED3DERR_INVALIDCALL;
4699 stateblock_init_contained_states(object);
4701 *stateblock = object;
4702 This->isRecordingState = FALSE;
4703 This->updateStateBlock = This->stateBlock;
4704 wined3d_stateblock_incref(This->updateStateBlock);
4706 TRACE("Returning stateblock %p.\n", *stateblock);
4708 return WINED3D_OK;
4711 /*****
4712 * Scene related functions
4713 *****/
4714 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4715 /* At the moment we have no need for any functionality at the beginning
4716 of a scene */
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 TRACE("(%p)\n", This);
4720 if(This->inScene) {
4721 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4722 return WINED3DERR_INVALIDCALL;
4724 This->inScene = TRUE;
4725 return WINED3D_OK;
4728 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4731 struct wined3d_context *context;
4733 TRACE("(%p)\n", This);
4735 if(!This->inScene) {
4736 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4737 return WINED3DERR_INVALIDCALL;
4740 context = context_acquire(This, NULL);
4741 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4742 wglFlush();
4743 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4744 * fails. */
4745 context_release(context);
4747 This->inScene = FALSE;
4748 return WINED3D_OK;
4751 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4752 const RECT *pSourceRect, const RECT *pDestRect,
4753 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4755 IWineD3DSwapChain *swapChain = NULL;
4756 int i;
4757 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4759 TRACE("iface %p.\n", iface);
4761 for(i = 0 ; i < swapchains ; i ++) {
4763 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4764 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4765 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4766 IWineD3DSwapChain_Release(swapChain);
4769 return WINED3D_OK;
4772 /* Do not call while under the GL lock. */
4773 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4774 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4776 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4777 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4778 RECT draw_rect;
4780 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4781 iface, rect_count, rects, flags, color, depth, stencil);
4783 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
4785 IWineD3DSurfaceImpl *ds = device->depth_stencil;
4786 if (!ds)
4788 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4789 /* TODO: What about depth stencil buffers without stencil bits? */
4790 return WINED3DERR_INVALIDCALL;
4792 else if (flags & WINED3DCLEAR_TARGET)
4794 if(ds->resource.width < device->render_targets[0]->resource.width ||
4795 ds->resource.height < device->render_targets[0]->resource.height)
4797 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
4798 return WINED3D_OK;
4803 device_get_draw_rect(device, &draw_rect);
4805 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4806 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4809 /*****
4810 * Drawing functions
4811 *****/
4813 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4814 WINED3DPRIMITIVETYPE primitive_type)
4816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4820 This->updateStateBlock->changed.primitive_type = TRUE;
4821 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4824 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4825 WINED3DPRIMITIVETYPE *primitive_type)
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4831 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4833 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4836 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4842 if (!This->stateBlock->state.vertex_declaration)
4844 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4845 return WINED3DERR_INVALIDCALL;
4848 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4849 if (This->stateBlock->state.user_stream)
4851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4852 This->stateBlock->state.user_stream = FALSE;
4855 if (This->stateBlock->state.load_base_vertex_index)
4857 This->stateBlock->state.load_base_vertex_index = 0;
4858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4860 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4861 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4862 return WINED3D_OK;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4868 struct wined3d_buffer *index_buffer;
4869 UINT idxStride = 2;
4870 GLuint vbo;
4872 index_buffer = This->stateBlock->state.index_buffer;
4873 if (!index_buffer)
4875 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4876 * without an index buffer set. (The first time at least...)
4877 * D3D8 simply dies, but I doubt it can do much harm to return
4878 * D3DERR_INVALIDCALL there as well. */
4879 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4880 return WINED3DERR_INVALIDCALL;
4883 if (!This->stateBlock->state.vertex_declaration)
4885 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4886 return WINED3DERR_INVALIDCALL;
4889 if (This->stateBlock->state.user_stream)
4891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4892 This->stateBlock->state.user_stream = FALSE;
4894 vbo = index_buffer->buffer_object;
4896 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4898 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4899 idxStride = 2;
4900 else
4901 idxStride = 4;
4903 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4905 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4909 drawPrimitive(This, index_count, startIndex, idxStride,
4910 vbo ? NULL : index_buffer->resource.allocatedMemory);
4912 return WINED3D_OK;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4916 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 struct wined3d_stream_state *stream;
4920 struct wined3d_buffer *vb;
4922 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4923 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4925 if (!This->stateBlock->state.vertex_declaration)
4927 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4928 return WINED3DERR_INVALIDCALL;
4931 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4932 stream = &This->stateBlock->state.streams[0];
4933 vb = stream->buffer;
4934 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4935 if (vb)
4936 wined3d_buffer_decref(vb);
4937 stream->offset = 0;
4938 stream->stride = VertexStreamZeroStride;
4939 This->stateBlock->state.user_stream = TRUE;
4940 This->stateBlock->state.load_base_vertex_index = 0;
4942 /* TODO: Only mark dirty if drawing from a different UP address */
4943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4945 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4947 /* MSDN specifies stream zero settings must be set to NULL */
4948 stream->buffer = NULL;
4949 stream->stride = 0;
4951 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4952 * the new stream sources or use UP drawing again
4954 return WINED3D_OK;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4958 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4959 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4961 int idxStride;
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4963 struct wined3d_stream_state *stream;
4964 struct wined3d_buffer *vb, *ib;
4966 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4967 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4969 if (!This->stateBlock->state.vertex_declaration)
4971 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4972 return WINED3DERR_INVALIDCALL;
4975 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4976 idxStride = 2;
4977 } else {
4978 idxStride = 4;
4981 stream = &This->stateBlock->state.streams[0];
4982 vb = stream->buffer;
4983 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4984 if (vb)
4985 wined3d_buffer_decref(vb);
4986 stream->offset = 0;
4987 stream->stride = VertexStreamZeroStride;
4988 This->stateBlock->state.user_stream = TRUE;
4990 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4991 This->stateBlock->state.base_vertex_index = 0;
4992 This->stateBlock->state.load_base_vertex_index = 0;
4993 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4997 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4999 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5000 stream->buffer = NULL;
5001 stream->stride = 0;
5002 ib = This->stateBlock->state.index_buffer;
5003 if (ib)
5005 wined3d_buffer_decref(ib);
5006 This->stateBlock->state.index_buffer = NULL;
5008 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5009 * SetStreamSource to specify a vertex buffer
5012 return WINED3D_OK;
5015 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5016 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5020 /* Mark the state dirty until we have nicer tracking
5021 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5022 * that value.
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5026 This->stateBlock->state.base_vertex_index = 0;
5027 This->up_strided = DrawPrimStrideData;
5028 drawPrimitive(This, vertex_count, 0, 0, NULL);
5029 This->up_strided = NULL;
5030 return WINED3D_OK;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5034 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5035 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5038 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5040 /* Mark the state dirty until we have nicer tracking
5041 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5042 * that value.
5044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5046 This->stateBlock->state.user_stream = TRUE;
5047 This->stateBlock->state.base_vertex_index = 0;
5048 This->up_strided = DrawPrimStrideData;
5049 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5050 This->up_strided = NULL;
5051 return WINED3D_OK;
5054 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5055 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5056 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5058 WINED3DLOCKED_BOX src;
5059 WINED3DLOCKED_BOX dst;
5060 HRESULT hr;
5062 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5063 iface, pSourceVolume, pDestinationVolume);
5065 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5066 * dirtification to improve loading performance.
5068 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5069 if (FAILED(hr)) return hr;
5070 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5071 if (FAILED(hr))
5073 IWineD3DVolume_Unmap(pSourceVolume);
5074 return hr;
5077 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5079 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5080 if (FAILED(hr))
5081 IWineD3DVolume_Unmap(pSourceVolume);
5082 else
5083 hr = IWineD3DVolume_Unmap(pSourceVolume);
5085 return hr;
5088 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5089 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5091 unsigned int level_count, i;
5092 WINED3DRESOURCETYPE type;
5093 HRESULT hr;
5095 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5097 /* Verify that the source and destination textures are non-NULL. */
5098 if (!src_texture || !dst_texture)
5100 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5101 return WINED3DERR_INVALIDCALL;
5104 if (src_texture == dst_texture)
5106 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5107 return WINED3DERR_INVALIDCALL;
5110 /* Verify that the source and destination textures are the same type. */
5111 type = IWineD3DBaseTexture_GetType(src_texture);
5112 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5114 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5115 return WINED3DERR_INVALIDCALL;
5118 /* Check that both textures have the identical numbers of levels. */
5119 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5120 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5122 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5123 return WINED3DERR_INVALIDCALL;
5126 /* Make sure that the destination texture is loaded. */
5127 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5128 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5130 /* Update every surface level of the texture. */
5131 switch (type)
5133 case WINED3DRTYPE_TEXTURE:
5135 IWineD3DSurface *src_surface;
5136 IWineD3DSurface *dst_surface;
5138 for (i = 0; i < level_count; ++i)
5140 src_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5141 (IWineD3DBaseTextureImpl *)src_texture, i));
5142 dst_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5143 (IWineD3DBaseTextureImpl *)dst_texture, i));
5144 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5145 if (FAILED(hr))
5147 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5148 return hr;
5151 break;
5154 case WINED3DRTYPE_CUBETEXTURE:
5156 IWineD3DSurface *src_surface;
5157 IWineD3DSurface *dst_surface;
5159 for (i = 0; i < level_count * 6; ++i)
5161 src_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5162 (IWineD3DBaseTextureImpl *)src_texture, i));
5163 dst_surface = (IWineD3DSurface *)surface_from_resource(basetexture_get_sub_resource(
5164 (IWineD3DBaseTextureImpl *)dst_texture, i));
5165 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5166 if (FAILED(hr))
5168 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5169 return hr;
5172 break;
5175 case WINED3DRTYPE_VOLUMETEXTURE:
5177 IWineD3DVolume *src_volume;
5178 IWineD3DVolume *dst_volume;
5180 for (i = 0; i < level_count; ++i)
5182 src_volume = (IWineD3DVolume *)surface_from_resource(basetexture_get_sub_resource(
5183 (IWineD3DBaseTextureImpl *)src_texture, i));
5184 dst_volume = (IWineD3DVolume *)surface_from_resource(basetexture_get_sub_resource(
5185 (IWineD3DBaseTextureImpl *)dst_texture, i));
5186 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5187 if (FAILED(hr))
5189 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5190 return hr;
5193 break;
5196 default:
5197 FIXME("Unsupported texture type %#x.\n", type);
5198 return WINED3DERR_INVALIDCALL;
5201 return WINED3D_OK;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5205 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5207 IWineD3DSwapChain *swapchain;
5208 HRESULT hr;
5210 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5212 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5213 if (FAILED(hr)) return hr;
5215 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5216 IWineD3DSwapChain_Release(swapchain);
5218 return hr;
5221 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 IWineD3DBaseTextureImpl *texture;
5224 DWORD i;
5225 const struct wined3d_state *state = &This->stateBlock->state;
5227 TRACE("(%p) : %p\n", This, pNumPasses);
5229 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5231 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5233 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5234 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5236 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5238 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5239 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5242 texture = state->textures[i];
5243 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5245 if (state->sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5247 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5248 return E_FAIL;
5250 if (state->sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5252 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5253 return E_FAIL;
5255 if (state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5256 && state->sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5258 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5259 return E_FAIL;
5263 if (state->render_states[WINED3DRS_ZENABLE] || state->render_states[WINED3DRS_ZWRITEENABLE] ||
5264 state->render_states[WINED3DRS_STENCILENABLE])
5266 IWineD3DSurfaceImpl *ds = This->depth_stencil;
5267 IWineD3DSurfaceImpl *target = This->render_targets[0];
5269 if(ds && target
5270 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
5272 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
5273 return WINED3DERR_CONFLICTINGRENDERSTATE;
5277 /* return a sensible default */
5278 *pNumPasses = 1;
5280 TRACE("returning D3D_OK\n");
5281 return WINED3D_OK;
5284 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5286 int i;
5288 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5290 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5291 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5292 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5294 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5299 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5301 int j;
5302 UINT NewSize;
5303 PALETTEENTRY **palettes;
5305 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5307 if (PaletteNumber >= MAX_PALETTES) {
5308 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5309 return WINED3DERR_INVALIDCALL;
5312 if (PaletteNumber >= This->NumberOfPalettes) {
5313 NewSize = This->NumberOfPalettes;
5314 do {
5315 NewSize *= 2;
5316 } while(PaletteNumber >= NewSize);
5317 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5318 if (!palettes) {
5319 ERR("Out of memory!\n");
5320 return E_OUTOFMEMORY;
5322 This->palettes = palettes;
5323 This->NumberOfPalettes = NewSize;
5326 if (!This->palettes[PaletteNumber]) {
5327 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5328 if (!This->palettes[PaletteNumber]) {
5329 ERR("Out of memory!\n");
5330 return E_OUTOFMEMORY;
5334 for (j = 0; j < 256; ++j) {
5335 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5336 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5337 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5338 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5340 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5341 TRACE("(%p) : returning\n", This);
5342 return WINED3D_OK;
5345 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5347 int j;
5348 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5349 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5350 /* What happens in such situation isn't documented; Native seems to silently abort
5351 on such conditions. Return Invalid Call. */
5352 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5353 return WINED3DERR_INVALIDCALL;
5355 for (j = 0; j < 256; ++j) {
5356 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5357 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5358 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5359 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5361 TRACE("(%p) : returning\n", This);
5362 return WINED3D_OK;
5365 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5368 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5369 (tested with reference rasterizer). Return Invalid Call. */
5370 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5371 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5372 return WINED3DERR_INVALIDCALL;
5374 /*TODO: stateblocks */
5375 if (This->currentPalette != PaletteNumber) {
5376 This->currentPalette = PaletteNumber;
5377 dirtify_p8_texture_samplers(This);
5379 TRACE("(%p) : returning\n", This);
5380 return WINED3D_OK;
5383 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5386 if (!PaletteNumber)
5388 WARN("(%p) : returning Invalid Call\n", This);
5389 return WINED3DERR_INVALIDCALL;
5391 /*TODO: stateblocks */
5392 *PaletteNumber = This->currentPalette;
5393 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5394 return WINED3D_OK;
5397 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5399 static BOOL warned;
5400 if (!warned)
5402 FIXME("(%p) : stub\n", This);
5403 warned = TRUE;
5406 This->softwareVertexProcessing = bSoftware;
5407 return WINED3D_OK;
5411 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 static BOOL warned;
5414 if (!warned)
5416 FIXME("(%p) : stub\n", This);
5417 warned = TRUE;
5419 return This->softwareVertexProcessing;
5422 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5423 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5425 IWineD3DSwapChain *swapchain;
5426 HRESULT hr;
5428 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5429 iface, swapchain_idx, raster_status);
5431 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5432 if (FAILED(hr))
5434 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5435 return hr;
5438 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5439 IWineD3DSwapChain_Release(swapchain);
5440 if (FAILED(hr))
5442 WARN("Failed to get raster status, hr %#x.\n", hr);
5443 return hr;
5446 return WINED3D_OK;
5449 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5451 static BOOL warned;
5452 if(nSegments != 0.0f) {
5453 if (!warned)
5455 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5456 warned = TRUE;
5459 return WINED3D_OK;
5462 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5464 static BOOL warned;
5465 if (!warned)
5467 FIXME("iface %p stub!\n", iface);
5468 warned = TRUE;
5470 return 0.0f;
5473 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5474 IWineD3DSurface *src_surface, const RECT *src_rect,
5475 IWineD3DSurface *dst_surface, const POINT *dst_point)
5477 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5478 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5480 const struct wined3d_format *src_format;
5481 const struct wined3d_format *dst_format;
5482 const struct wined3d_gl_info *gl_info;
5483 struct wined3d_context *context;
5484 const unsigned char *data;
5485 UINT update_w, update_h;
5486 CONVERT_TYPES convert;
5487 UINT src_w, src_h;
5488 UINT dst_x, dst_y;
5489 DWORD sampler;
5490 struct wined3d_format format;
5492 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5493 iface, src_surface, wine_dbgstr_rect(src_rect),
5494 dst_surface, wine_dbgstr_point(dst_point));
5496 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5498 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5499 src_surface, dst_surface);
5500 return WINED3DERR_INVALIDCALL;
5503 src_format = src_impl->resource.format;
5504 dst_format = dst_impl->resource.format;
5506 if (src_format->id != dst_format->id)
5508 WARN("Source and destination surfaces should have the same format.\n");
5509 return WINED3DERR_INVALIDCALL;
5512 dst_x = dst_point ? dst_point->x : 0;
5513 dst_y = dst_point ? dst_point->y : 0;
5515 /* This call loads the OpenGL surface directly, instead of copying the
5516 * surface to the destination's sysmem copy. If surface conversion is
5517 * needed, use BltFast instead to copy in sysmem and use regular surface
5518 * loading. */
5519 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5520 if (convert != NO_CONVERSION || format.convert)
5521 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5523 context = context_acquire(This, NULL);
5524 gl_info = context->gl_info;
5526 ENTER_GL();
5527 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5528 checkGLcall("glActiveTextureARB");
5529 LEAVE_GL();
5531 /* Make sure the surface is loaded and up to date */
5532 surface_internal_preload(dst_impl, SRGB_RGB);
5533 surface_bind(dst_impl, gl_info, FALSE);
5535 src_w = src_impl->resource.width;
5536 src_h = src_impl->resource.height;
5537 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5538 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5540 data = src_impl->resource.allocatedMemory;
5541 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5543 ENTER_GL();
5545 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5547 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5548 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5549 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5551 if (src_rect)
5553 data += (src_rect->top / src_format->block_height) * src_pitch;
5554 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5557 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5558 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5559 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5561 if (row_length == src_pitch)
5563 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5564 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5566 else
5568 UINT row, y;
5570 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5571 * can't use the unpack row length like below. */
5572 for (row = 0, y = dst_y; row < row_count; ++row)
5574 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5575 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5576 y += src_format->block_height;
5577 data += src_pitch;
5580 checkGLcall("glCompressedTexSubImage2DARB");
5582 else
5584 if (src_rect)
5586 data += src_rect->top * src_w * src_format->byte_count;
5587 data += src_rect->left * src_format->byte_count;
5590 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5591 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5592 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5594 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5595 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5596 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5597 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5598 checkGLcall("glTexSubImage2D");
5601 LEAVE_GL();
5602 context_release(context);
5604 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5605 sampler = This->rev_tex_unit_map[0];
5606 if (sampler != WINED3D_UNMAPPED_STAGE)
5608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5611 return WINED3D_OK;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 struct WineD3DRectPatch *patch;
5617 GLenum old_primitive_type;
5618 unsigned int i;
5619 struct list *e;
5620 BOOL found;
5621 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5623 if(!(Handle || pRectPatchInfo)) {
5624 /* TODO: Write a test for the return value, thus the FIXME */
5625 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5626 return WINED3DERR_INVALIDCALL;
5629 if(Handle) {
5630 i = PATCHMAP_HASHFUNC(Handle);
5631 found = FALSE;
5632 LIST_FOR_EACH(e, &This->patches[i]) {
5633 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5634 if(patch->Handle == Handle) {
5635 found = TRUE;
5636 break;
5640 if(!found) {
5641 TRACE("Patch does not exist. Creating a new one\n");
5642 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5643 patch->Handle = Handle;
5644 list_add_head(&This->patches[i], &patch->entry);
5645 } else {
5646 TRACE("Found existing patch %p\n", patch);
5648 } else {
5649 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5650 * attributes we have to tesselate, read back, and draw. This needs a patch
5651 * management structure instance. Create one.
5653 * A possible improvement is to check if a vertex shader is used, and if not directly
5654 * draw the patch.
5656 FIXME("Drawing an uncached patch. This is slow\n");
5657 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5660 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5661 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5662 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5664 HRESULT hr;
5665 TRACE("Tesselation density or patch info changed, retesselating\n");
5667 if(pRectPatchInfo) {
5668 patch->RectPatchInfo = *pRectPatchInfo;
5670 patch->numSegs[0] = pNumSegs[0];
5671 patch->numSegs[1] = pNumSegs[1];
5672 patch->numSegs[2] = pNumSegs[2];
5673 patch->numSegs[3] = pNumSegs[3];
5675 hr = tesselate_rectpatch(This, patch);
5676 if(FAILED(hr)) {
5677 WARN("Patch tesselation failed\n");
5679 /* Do not release the handle to store the params of the patch */
5680 if(!Handle) {
5681 HeapFree(GetProcessHeap(), 0, patch);
5683 return hr;
5687 This->currentPatch = patch;
5688 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5689 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5690 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5691 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5692 This->currentPatch = NULL;
5694 /* Destroy uncached patches */
5695 if(!Handle) {
5696 HeapFree(GetProcessHeap(), 0, patch->mem);
5697 HeapFree(GetProcessHeap(), 0, patch);
5699 return WINED3D_OK;
5702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5703 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5705 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5706 iface, handle, segment_count, patch_info);
5708 return WINED3D_OK;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 int i;
5714 struct WineD3DRectPatch *patch;
5715 struct list *e;
5716 TRACE("(%p) Handle(%d)\n", This, Handle);
5718 i = PATCHMAP_HASHFUNC(Handle);
5719 LIST_FOR_EACH(e, &This->patches[i]) {
5720 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5721 if(patch->Handle == Handle) {
5722 TRACE("Deleting patch %p\n", patch);
5723 list_remove(&patch->entry);
5724 HeapFree(GetProcessHeap(), 0, patch->mem);
5725 HeapFree(GetProcessHeap(), 0, patch);
5726 return WINED3D_OK;
5730 /* TODO: Write a test for the return value */
5731 FIXME("Attempt to destroy nonexistent patch\n");
5732 return WINED3DERR_INVALIDCALL;
5735 /* Do not call while under the GL lock. */
5736 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5737 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5739 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5741 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5742 iface, surface, wine_dbgstr_rect(rect),
5743 color->r, color->g, color->b, color->a);
5745 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5747 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5748 return WINED3DERR_INVALIDCALL;
5751 return surface_color_fill(s, rect, color);
5754 /* Do not call while under the GL lock. */
5755 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5756 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5758 struct wined3d_resource *resource;
5759 HRESULT hr;
5761 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5762 if (FAILED(hr))
5764 ERR("Failed to get resource, hr %#x\n", hr);
5765 return;
5768 if (resource->resourceType != WINED3DRTYPE_SURFACE)
5770 FIXME("Only supported on surface resources\n");
5771 return;
5774 hr = surface_color_fill(surface_from_resource(resource), NULL, color);
5775 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5778 /* rendertarget and depth stencil functions */
5779 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5780 DWORD render_target_idx, IWineD3DSurface **render_target)
5782 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5784 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5785 iface, render_target_idx, render_target);
5787 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5789 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5790 return WINED3DERR_INVALIDCALL;
5793 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5794 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5796 TRACE("Returning render target %p.\n", *render_target);
5798 return WINED3D_OK;
5801 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5803 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5805 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5807 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5808 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5809 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5810 IWineD3DSurface_AddRef(*depth_stencil);
5812 return WINED3D_OK;
5815 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5816 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5818 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5819 IWineD3DSurfaceImpl *prev;
5821 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5822 iface, render_target_idx, render_target, set_viewport);
5824 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5826 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5827 return WINED3DERR_INVALIDCALL;
5830 prev = device->render_targets[render_target_idx];
5831 if (render_target == (IWineD3DSurface *)prev)
5833 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5834 return WINED3D_OK;
5837 /* Render target 0 can't be set to NULL. */
5838 if (!render_target && !render_target_idx)
5840 WARN("Trying to set render target 0 to NULL.\n");
5841 return WINED3DERR_INVALIDCALL;
5844 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5846 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5847 return WINED3DERR_INVALIDCALL;
5850 if (render_target) IWineD3DSurface_AddRef(render_target);
5851 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5852 /* Release after the assignment, to prevent device_resource_released()
5853 * from seeing the surface as still in use. */
5854 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5856 /* Render target 0 is special. */
5857 if (!render_target_idx && set_viewport)
5859 /* Set the viewport and scissor rectangles, if requested. Tests show
5860 * that stateblock recording is ignored, the change goes directly
5861 * into the primary stateblock. */
5862 device->stateBlock->state.viewport.Height = device->render_targets[0]->resource.height;
5863 device->stateBlock->state.viewport.Width = device->render_targets[0]->resource.width;
5864 device->stateBlock->state.viewport.X = 0;
5865 device->stateBlock->state.viewport.Y = 0;
5866 device->stateBlock->state.viewport.MaxZ = 1.0f;
5867 device->stateBlock->state.viewport.MinZ = 0.0f;
5868 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5870 device->stateBlock->state.scissor_rect.top = 0;
5871 device->stateBlock->state.scissor_rect.left = 0;
5872 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5873 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5874 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5877 return WINED3D_OK;
5880 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 IWineD3DSurfaceImpl *tmp;
5885 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5887 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5889 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5890 return WINED3D_OK;
5893 if (This->depth_stencil)
5895 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5896 || This->depth_stencil->flags & SFLAG_DISCARD)
5898 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5899 This->depth_stencil->resource.width,
5900 This->depth_stencil->resource.height);
5901 if (This->depth_stencil == This->onscreen_depth_stencil)
5903 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5904 This->onscreen_depth_stencil = NULL;
5909 tmp = This->depth_stencil;
5910 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5911 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5912 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5914 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5916 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5922 return WINED3D_OK;
5925 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5926 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5929 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5930 WINED3DLOCKED_RECT lockedRect;
5932 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5933 iface, XHotSpot, YHotSpot, cursor_image);
5935 /* some basic validation checks */
5936 if (This->cursorTexture)
5938 struct wined3d_context *context = context_acquire(This, NULL);
5939 ENTER_GL();
5940 glDeleteTextures(1, &This->cursorTexture);
5941 LEAVE_GL();
5942 context_release(context);
5943 This->cursorTexture = 0;
5946 if (s->resource.width == 32 && s->resource.height == 32)
5947 This->haveHardwareCursor = TRUE;
5948 else
5949 This->haveHardwareCursor = FALSE;
5951 if (cursor_image)
5953 WINED3DLOCKED_RECT rect;
5955 /* MSDN: Cursor must be A8R8G8B8 */
5956 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5958 WARN("surface %p has an invalid format.\n", cursor_image);
5959 return WINED3DERR_INVALIDCALL;
5962 /* MSDN: Cursor must be smaller than the display mode */
5963 if (s->resource.width > This->ddraw_width
5964 || s->resource.height > This->ddraw_height)
5966 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5967 s, s->resource.width, s->resource.height, This->ddraw_width, This->ddraw_height);
5968 return WINED3DERR_INVALIDCALL;
5971 if (!This->haveHardwareCursor) {
5972 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5974 /* Do not store the surface's pointer because the application may
5975 * release it after setting the cursor image. Windows doesn't
5976 * addref the set surface, so we can't do this either without
5977 * creating circular refcount dependencies. Copy out the gl texture
5978 * instead.
5980 This->cursorWidth = s->resource.width;
5981 This->cursorHeight = s->resource.height;
5982 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5984 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5985 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5986 struct wined3d_context *context;
5987 char *mem, *bits = rect.pBits;
5988 GLint intfmt = format->glInternal;
5989 GLint gl_format = format->glFormat;
5990 GLint type = format->glType;
5991 INT height = This->cursorHeight;
5992 INT width = This->cursorWidth;
5993 INT bpp = format->byte_count;
5994 DWORD sampler;
5995 INT i;
5997 /* Reformat the texture memory (pitch and width can be
5998 * different) */
5999 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6000 for(i = 0; i < height; i++)
6001 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6002 IWineD3DSurface_Unmap(cursor_image);
6004 context = context_acquire(This, NULL);
6006 ENTER_GL();
6008 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6010 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6011 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6014 /* Make sure that a proper texture unit is selected */
6015 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6016 checkGLcall("glActiveTextureARB");
6017 sampler = This->rev_tex_unit_map[0];
6018 if (sampler != WINED3D_UNMAPPED_STAGE)
6020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6022 /* Create a new cursor texture */
6023 glGenTextures(1, &This->cursorTexture);
6024 checkGLcall("glGenTextures");
6025 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6026 checkGLcall("glBindTexture");
6027 /* Copy the bitmap memory into the cursor texture */
6028 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6029 checkGLcall("glTexImage2D");
6030 HeapFree(GetProcessHeap(), 0, mem);
6032 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6038 LEAVE_GL();
6040 context_release(context);
6042 else
6044 FIXME("A cursor texture was not returned.\n");
6045 This->cursorTexture = 0;
6048 else
6050 /* Draw a hardware cursor */
6051 ICONINFO cursorInfo;
6052 HCURSOR cursor;
6053 /* Create and clear maskBits because it is not needed for
6054 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6055 * chunks. */
6056 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6057 (s->resource.width * s->resource.height / 8));
6058 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6059 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6060 TRACE("width: %u height: %u.\n", s->resource.width, s->resource.height);
6062 cursorInfo.fIcon = FALSE;
6063 cursorInfo.xHotspot = XHotSpot;
6064 cursorInfo.yHotspot = YHotSpot;
6065 cursorInfo.hbmMask = CreateBitmap(s->resource.width, s->resource.height, 1, 1, maskBits);
6066 cursorInfo.hbmColor = CreateBitmap(s->resource.width, s->resource.height, 1, 32, lockedRect.pBits);
6067 IWineD3DSurface_Unmap(cursor_image);
6068 /* Create our cursor and clean up. */
6069 cursor = CreateIconIndirect(&cursorInfo);
6070 SetCursor(cursor);
6071 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6072 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6073 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6074 This->hardwareCursor = cursor;
6075 HeapFree(GetProcessHeap(), 0, maskBits);
6079 This->xHotSpot = XHotSpot;
6080 This->yHotSpot = YHotSpot;
6081 return WINED3D_OK;
6084 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6085 int XScreenSpace, int YScreenSpace, DWORD flags)
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6089 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6090 iface, XScreenSpace, YScreenSpace, flags);
6092 This->xScreenSpace = XScreenSpace;
6093 This->yScreenSpace = YScreenSpace;
6096 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6098 BOOL oldVisible = This->bCursorVisible;
6099 POINT pt;
6101 TRACE("(%p) : visible(%d)\n", This, bShow);
6104 * When ShowCursor is first called it should make the cursor appear at the OS's last
6105 * known cursor position. Because of this, some applications just repetitively call
6106 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6108 GetCursorPos(&pt);
6109 This->xScreenSpace = pt.x;
6110 This->yScreenSpace = pt.y;
6112 if (This->haveHardwareCursor) {
6113 This->bCursorVisible = bShow;
6114 if (bShow)
6115 SetCursor(This->hardwareCursor);
6116 else
6117 SetCursor(NULL);
6119 else
6121 if (This->cursorTexture)
6122 This->bCursorVisible = bShow;
6125 return oldVisible;
6128 static HRESULT WINAPI evict_managed_resource(struct wined3d_resource *resource, void *data)
6130 TRACE("checking resource %p for eviction\n", resource);
6132 if (resource->pool == WINED3DPOOL_MANAGED)
6134 TRACE("Evicting %p.\n", resource);
6135 resource->resource_ops->resource_unload(resource);
6138 return S_OK;
6141 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6143 TRACE("iface %p.\n", iface);
6145 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6146 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6147 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6149 return WINED3D_OK;
6152 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6154 IWineD3DDeviceImpl *device = surface->resource.device;
6155 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6157 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6158 if (surface->flags & SFLAG_DIBSECTION)
6160 /* Release the DC */
6161 SelectObject(surface->hDC, surface->dib.holdbitmap);
6162 DeleteDC(surface->hDC);
6163 /* Release the DIB section */
6164 DeleteObject(surface->dib.DIBsection);
6165 surface->dib.bitmap_data = NULL;
6166 surface->resource.allocatedMemory = NULL;
6167 surface->flags &= ~SFLAG_DIBSECTION;
6169 surface->resource.width = pPresentationParameters->BackBufferWidth;
6170 surface->resource.height = pPresentationParameters->BackBufferHeight;
6171 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6172 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6174 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6175 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6176 } else {
6177 surface->pow2Width = surface->pow2Height = 1;
6178 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6179 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6182 if (surface->texture_name)
6184 struct wined3d_context *context = context_acquire(device, NULL);
6185 ENTER_GL();
6186 glDeleteTextures(1, &surface->texture_name);
6187 LEAVE_GL();
6188 context_release(context);
6189 surface->texture_name = 0;
6190 surface->flags &= ~SFLAG_CLIENT;
6192 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6193 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6195 surface->flags |= SFLAG_NONPOW2;
6197 else
6199 surface->flags &= ~SFLAG_NONPOW2;
6201 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6202 surface->resource.allocatedMemory = NULL;
6203 surface->resource.heapMemory = NULL;
6204 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6206 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6207 * to a FBO */
6208 if (!surface_init_sysmem(surface))
6210 return E_OUTOFMEMORY;
6212 return WINED3D_OK;
6215 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6217 UINT i, count;
6218 WINED3DDISPLAYMODE m;
6219 HRESULT hr;
6221 /* All Windowed modes are supported, as is leaving the current mode */
6222 if(pp->Windowed) return TRUE;
6223 if(!pp->BackBufferWidth) return TRUE;
6224 if(!pp->BackBufferHeight) return TRUE;
6226 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6227 for (i = 0; i < count; ++i)
6229 memset(&m, 0, sizeof(m));
6230 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6231 if (FAILED(hr))
6232 ERR("Failed to enumerate adapter mode.\n");
6233 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6234 /* Mode found, it is supported. */
6235 return TRUE;
6237 /* Mode not found -> not supported */
6238 return FALSE;
6241 /* Do not call while under the GL lock. */
6242 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6244 const struct wined3d_gl_info *gl_info;
6245 struct wined3d_context *context;
6246 IWineD3DBaseShaderImpl *shader;
6248 context = context_acquire(device, NULL);
6249 gl_info = context->gl_info;
6251 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, device_unload_resource, NULL);
6252 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6254 device->shader_backend->shader_destroy(shader);
6257 ENTER_GL();
6258 if (device->depth_blt_texture)
6260 glDeleteTextures(1, &device->depth_blt_texture);
6261 device->depth_blt_texture = 0;
6263 if (device->depth_blt_rb)
6265 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6266 device->depth_blt_rb = 0;
6267 device->depth_blt_rb_w = 0;
6268 device->depth_blt_rb_h = 0;
6270 LEAVE_GL();
6272 device->blitter->free_private(device);
6273 device->frag_pipe->free_private(device);
6274 device->shader_backend->shader_free_private(device);
6275 destroy_dummy_textures(device, gl_info);
6277 context_release(context);
6279 while (device->numContexts)
6281 context_destroy(device, device->contexts[0]);
6283 HeapFree(GetProcessHeap(), 0, swapchain->context);
6284 swapchain->context = NULL;
6285 swapchain->num_contexts = 0;
6288 /* Do not call while under the GL lock. */
6289 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6291 struct wined3d_context *context;
6292 HRESULT hr;
6293 IWineD3DSurfaceImpl *target;
6295 /* Recreate the primary swapchain's context */
6296 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6297 if (!swapchain->context)
6299 ERR("Failed to allocate memory for swapchain context array.\n");
6300 return E_OUTOFMEMORY;
6303 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6304 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6306 WARN("Failed to create context.\n");
6307 HeapFree(GetProcessHeap(), 0, swapchain->context);
6308 return E_FAIL;
6311 swapchain->context[0] = context;
6312 swapchain->num_contexts = 1;
6313 create_dummy_textures(device);
6314 context_release(context);
6316 hr = device->shader_backend->shader_alloc_private(device);
6317 if (FAILED(hr))
6319 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6320 goto err;
6323 hr = device->frag_pipe->alloc_private(device);
6324 if (FAILED(hr))
6326 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6327 device->shader_backend->shader_free_private(device);
6328 goto err;
6331 hr = device->blitter->alloc_private(device);
6332 if (FAILED(hr))
6334 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6335 device->frag_pipe->free_private(device);
6336 device->shader_backend->shader_free_private(device);
6337 goto err;
6340 return WINED3D_OK;
6342 err:
6343 context_acquire(device, NULL);
6344 destroy_dummy_textures(device, context->gl_info);
6345 context_release(context);
6346 context_destroy(device, context);
6347 HeapFree(GetProcessHeap(), 0, swapchain->context);
6348 swapchain->num_contexts = 0;
6349 return hr;
6352 /* Do not call while under the GL lock. */
6353 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6354 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6357 IWineD3DSwapChainImpl *swapchain;
6358 HRESULT hr;
6359 BOOL DisplayModeChanged = FALSE;
6360 WINED3DDISPLAYMODE mode;
6361 TRACE("(%p)\n", This);
6363 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6364 if(FAILED(hr)) {
6365 ERR("Failed to get the first implicit swapchain\n");
6366 return hr;
6369 if(!is_display_mode_supported(This, pPresentationParameters)) {
6370 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6371 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6372 pPresentationParameters->BackBufferHeight);
6373 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6374 return WINED3DERR_INVALIDCALL;
6377 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6378 * on an existing gl context, so there's no real need for recreation.
6380 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6382 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6384 TRACE("New params:\n");
6385 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6386 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6387 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6388 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6389 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6390 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6391 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6392 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6393 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6394 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6395 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6396 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6397 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6399 /* No special treatment of these parameters. Just store them */
6400 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6401 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6402 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6403 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6405 /* What to do about these? */
6406 if (pPresentationParameters->BackBufferCount
6407 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6408 ERR("Cannot change the back buffer count yet\n");
6410 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6411 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6412 ERR("Cannot change the back buffer format yet\n");
6415 if (pPresentationParameters->hDeviceWindow
6416 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6417 ERR("Cannot change the device window yet\n");
6419 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6421 HRESULT hrc;
6423 TRACE("Creating the depth stencil buffer\n");
6425 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6426 pPresentationParameters->BackBufferWidth,
6427 pPresentationParameters->BackBufferHeight,
6428 pPresentationParameters->AutoDepthStencilFormat,
6429 pPresentationParameters->MultiSampleType,
6430 pPresentationParameters->MultiSampleQuality,
6431 FALSE,
6432 (IWineD3DSurface **)&This->auto_depth_stencil);
6434 if (FAILED(hrc)) {
6435 ERR("Failed to create the depth stencil buffer\n");
6436 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6437 return WINED3DERR_INVALIDCALL;
6441 if (This->onscreen_depth_stencil)
6443 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6444 This->onscreen_depth_stencil = NULL;
6447 /* Reset the depth stencil */
6448 if (pPresentationParameters->EnableAutoDepthStencil)
6449 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6450 else
6451 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6453 TRACE("Resetting stateblock\n");
6454 wined3d_stateblock_decref(This->updateStateBlock);
6455 wined3d_stateblock_decref(This->stateBlock);
6457 delete_opengl_contexts(This, swapchain);
6459 if(pPresentationParameters->Windowed) {
6460 mode.Width = swapchain->orig_width;
6461 mode.Height = swapchain->orig_height;
6462 mode.RefreshRate = 0;
6463 mode.Format = swapchain->presentParms.BackBufferFormat;
6464 } else {
6465 mode.Width = pPresentationParameters->BackBufferWidth;
6466 mode.Height = pPresentationParameters->BackBufferHeight;
6467 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6468 mode.Format = swapchain->presentParms.BackBufferFormat;
6471 /* Should Width == 800 && Height == 0 set 800x600? */
6472 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6473 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6474 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6476 UINT i;
6478 if(!pPresentationParameters->Windowed) {
6479 DisplayModeChanged = TRUE;
6481 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6482 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6484 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6485 if(FAILED(hr))
6487 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6488 return hr;
6491 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6493 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6494 if(FAILED(hr))
6496 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6497 return hr;
6500 if (This->auto_depth_stencil)
6502 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6503 if(FAILED(hr))
6505 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6506 return hr;
6511 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6512 || DisplayModeChanged)
6514 BOOL filter = This->filter_messages;
6515 This->filter_messages = TRUE;
6517 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6519 if (!pPresentationParameters->Windowed)
6521 if (swapchain->presentParms.Windowed)
6523 HWND focus_window = This->createParms.hFocusWindow;
6524 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6525 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6527 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6528 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6529 return hr;
6532 /* switch from windowed to fs */
6533 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6534 pPresentationParameters->BackBufferWidth,
6535 pPresentationParameters->BackBufferHeight);
6537 else
6539 /* Fullscreen -> fullscreen mode change */
6540 MoveWindow(swapchain->device_window, 0, 0,
6541 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6542 TRUE);
6545 else if (!swapchain->presentParms.Windowed)
6547 /* Fullscreen -> windowed switch */
6548 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6549 IWineD3DDevice_ReleaseFocusWindow(iface);
6551 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6553 This->filter_messages = filter;
6555 else if (!pPresentationParameters->Windowed)
6557 DWORD style = This->style, exStyle = This->exStyle;
6558 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6559 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6560 * Reset to clear up their mess. Guild Wars also loses the device during that.
6562 This->style = 0;
6563 This->exStyle = 0;
6564 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6565 pPresentationParameters->BackBufferWidth,
6566 pPresentationParameters->BackBufferHeight);
6567 This->style = style;
6568 This->exStyle = exStyle;
6571 /* Note: No parent needed for initial internal stateblock */
6572 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6573 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6574 else TRACE("Created stateblock %p\n", This->stateBlock);
6575 This->updateStateBlock = This->stateBlock;
6576 wined3d_stateblock_incref(This->updateStateBlock);
6578 stateblock_init_default_state(This->stateBlock);
6580 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6582 RECT client_rect;
6583 GetClientRect(swapchain->win_handle, &client_rect);
6585 if(!swapchain->presentParms.BackBufferCount)
6587 TRACE("Single buffered rendering\n");
6588 swapchain->render_to_fbo = FALSE;
6590 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6591 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6593 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6594 swapchain->presentParms.BackBufferWidth,
6595 swapchain->presentParms.BackBufferHeight,
6596 client_rect.right, client_rect.bottom);
6597 swapchain->render_to_fbo = TRUE;
6599 else
6601 TRACE("Rendering directly to GL_BACK\n");
6602 swapchain->render_to_fbo = FALSE;
6606 hr = create_primary_opengl_context(This, swapchain);
6607 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6609 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6610 * first use
6612 return hr;
6615 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6617 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6619 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6621 return WINED3D_OK;
6625 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6627 TRACE("(%p) : pParameters %p\n", This, pParameters);
6629 *pParameters = This->createParms;
6630 return WINED3D_OK;
6633 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6634 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6636 IWineD3DSwapChain *swapchain;
6638 TRACE("Relaying to swapchain\n");
6640 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6642 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6643 IWineD3DSwapChain_Release(swapchain);
6647 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6648 IWineD3DSwapChain *swapchain;
6650 TRACE("Relaying to swapchain\n");
6652 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6653 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6654 IWineD3DSwapChain_Release(swapchain);
6658 void device_resource_add(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6660 TRACE("device %p, resource %p.\n", device, resource);
6662 list_add_head(&device->resources, &resource->resource_list_entry);
6665 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6667 TRACE("device %p, resource %p.\n", device, resource);
6669 list_remove(&resource->resource_list_entry);
6672 void device_resource_released(struct IWineD3DDeviceImpl *device, struct wined3d_resource *resource)
6674 WINED3DRESOURCETYPE type = resource->resourceType;
6675 unsigned int i;
6677 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6679 context_resource_released(device, resource, type);
6681 switch (type)
6683 case WINED3DRTYPE_SURFACE:
6685 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
6687 if (!device->d3d_initialized) break;
6689 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6691 if (device->render_targets[i] == surface)
6693 ERR("Surface %p is still in use as render target %u.\n", surface, i);
6694 device->render_targets[i] = NULL;
6698 if (device->depth_stencil == surface)
6700 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
6701 device->depth_stencil = NULL;
6704 break;
6706 case WINED3DRTYPE_TEXTURE:
6707 case WINED3DRTYPE_CUBETEXTURE:
6708 case WINED3DRTYPE_VOLUMETEXTURE:
6709 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6711 IWineD3DBaseTextureImpl *texture = basetexture_from_resource(resource);
6713 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
6715 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6716 texture, device->stateBlock, i);
6717 device->stateBlock->state.textures[i] = NULL;
6720 if (device->updateStateBlock != device->stateBlock
6721 && device->updateStateBlock->state.textures[i] == texture)
6723 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6724 texture, device->updateStateBlock, i);
6725 device->updateStateBlock->state.textures[i] = NULL;
6728 break;
6730 case WINED3DRTYPE_BUFFER:
6732 struct wined3d_buffer *buffer = buffer_from_resource(resource);
6734 for (i = 0; i < MAX_STREAMS; ++i)
6736 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
6738 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6739 buffer, device->stateBlock, i);
6740 device->stateBlock->state.streams[i].buffer = NULL;
6743 if (device->updateStateBlock != device->stateBlock
6744 && device->updateStateBlock->state.streams[i].buffer == buffer)
6746 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6747 buffer, device->updateStateBlock, i);
6748 device->updateStateBlock->state.streams[i].buffer = NULL;
6753 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
6755 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6756 buffer, device->stateBlock);
6757 device->stateBlock->state.index_buffer = NULL;
6760 if (device->updateStateBlock != device->stateBlock
6761 && device->updateStateBlock->state.index_buffer == buffer)
6763 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6764 buffer, device->updateStateBlock);
6765 device->updateStateBlock->state.index_buffer = NULL;
6768 break;
6770 default:
6771 break;
6774 /* Remove the resource from the resourceStore */
6775 device_resource_remove(device, resource);
6777 TRACE("Resource released.\n");
6780 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface,
6781 D3DCB_ENUMRESOURCES callback, void *data)
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 struct wined3d_resource *resource, *cursor;
6786 TRACE("iface %p, callback %p, data %p.\n", iface, callback, data);
6788 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, struct wined3d_resource, resource_list_entry)
6790 TRACE("enumerating resource %p.\n", resource);
6791 if (callback(resource, data) == S_FALSE)
6793 TRACE("Canceling enumeration.\n");
6794 break;
6798 return WINED3D_OK;
6801 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6804 struct wined3d_resource *resource;
6806 LIST_FOR_EACH_ENTRY(resource, &This->resources, struct wined3d_resource, resource_list_entry)
6808 if (resource->resourceType == WINED3DRTYPE_SURFACE)
6810 IWineD3DSurfaceImpl *s = surface_from_resource(resource);
6812 if (s->hDC == dc)
6814 TRACE("Found surface %p for dc %p.\n", s, dc);
6815 *surface = (IWineD3DSurface *)s;
6816 return WINED3D_OK;
6821 return WINED3DERR_INVALIDCALL;
6824 /**********************************************************
6825 * IWineD3DDevice VTbl follows
6826 **********************************************************/
6828 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6830 /*** IUnknown methods ***/
6831 IWineD3DDeviceImpl_QueryInterface,
6832 IWineD3DDeviceImpl_AddRef,
6833 IWineD3DDeviceImpl_Release,
6834 /*** IWineD3DDevice methods ***/
6835 /*** Creation methods**/
6836 IWineD3DDeviceImpl_CreateBuffer,
6837 IWineD3DDeviceImpl_CreateVertexBuffer,
6838 IWineD3DDeviceImpl_CreateIndexBuffer,
6839 IWineD3DDeviceImpl_CreateStateBlock,
6840 IWineD3DDeviceImpl_CreateSurface,
6841 IWineD3DDeviceImpl_CreateRendertargetView,
6842 IWineD3DDeviceImpl_CreateTexture,
6843 IWineD3DDeviceImpl_CreateVolumeTexture,
6844 IWineD3DDeviceImpl_CreateVolume,
6845 IWineD3DDeviceImpl_CreateCubeTexture,
6846 IWineD3DDeviceImpl_CreateQuery,
6847 IWineD3DDeviceImpl_CreateSwapChain,
6848 IWineD3DDeviceImpl_CreateVertexDeclaration,
6849 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6850 IWineD3DDeviceImpl_CreateVertexShader,
6851 IWineD3DDeviceImpl_CreateGeometryShader,
6852 IWineD3DDeviceImpl_CreatePixelShader,
6853 IWineD3DDeviceImpl_CreatePalette,
6854 /*** Odd functions **/
6855 IWineD3DDeviceImpl_Init3D,
6856 IWineD3DDeviceImpl_InitGDI,
6857 IWineD3DDeviceImpl_Uninit3D,
6858 IWineD3DDeviceImpl_UninitGDI,
6859 IWineD3DDeviceImpl_SetMultithreaded,
6860 IWineD3DDeviceImpl_EvictManagedResources,
6861 IWineD3DDeviceImpl_GetAvailableTextureMem,
6862 IWineD3DDeviceImpl_GetBackBuffer,
6863 IWineD3DDeviceImpl_GetCreationParameters,
6864 IWineD3DDeviceImpl_GetDeviceCaps,
6865 IWineD3DDeviceImpl_GetDirect3D,
6866 IWineD3DDeviceImpl_GetDisplayMode,
6867 IWineD3DDeviceImpl_SetDisplayMode,
6868 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6869 IWineD3DDeviceImpl_GetRasterStatus,
6870 IWineD3DDeviceImpl_GetSwapChain,
6871 IWineD3DDeviceImpl_Reset,
6872 IWineD3DDeviceImpl_SetDialogBoxMode,
6873 IWineD3DDeviceImpl_SetCursorProperties,
6874 IWineD3DDeviceImpl_SetCursorPosition,
6875 IWineD3DDeviceImpl_ShowCursor,
6876 /*** Getters and setters **/
6877 IWineD3DDeviceImpl_SetClipPlane,
6878 IWineD3DDeviceImpl_GetClipPlane,
6879 IWineD3DDeviceImpl_SetClipStatus,
6880 IWineD3DDeviceImpl_GetClipStatus,
6881 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6882 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6883 IWineD3DDeviceImpl_SetDepthStencilSurface,
6884 IWineD3DDeviceImpl_GetDepthStencilSurface,
6885 IWineD3DDeviceImpl_SetGammaRamp,
6886 IWineD3DDeviceImpl_GetGammaRamp,
6887 IWineD3DDeviceImpl_SetIndexBuffer,
6888 IWineD3DDeviceImpl_GetIndexBuffer,
6889 IWineD3DDeviceImpl_SetBaseVertexIndex,
6890 IWineD3DDeviceImpl_GetBaseVertexIndex,
6891 IWineD3DDeviceImpl_SetLight,
6892 IWineD3DDeviceImpl_GetLight,
6893 IWineD3DDeviceImpl_SetLightEnable,
6894 IWineD3DDeviceImpl_GetLightEnable,
6895 IWineD3DDeviceImpl_SetMaterial,
6896 IWineD3DDeviceImpl_GetMaterial,
6897 IWineD3DDeviceImpl_SetNPatchMode,
6898 IWineD3DDeviceImpl_GetNPatchMode,
6899 IWineD3DDeviceImpl_SetPaletteEntries,
6900 IWineD3DDeviceImpl_GetPaletteEntries,
6901 IWineD3DDeviceImpl_SetPixelShader,
6902 IWineD3DDeviceImpl_GetPixelShader,
6903 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6904 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6905 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6906 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6907 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6908 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6909 IWineD3DDeviceImpl_SetRenderState,
6910 IWineD3DDeviceImpl_GetRenderState,
6911 IWineD3DDeviceImpl_SetRenderTarget,
6912 IWineD3DDeviceImpl_GetRenderTarget,
6913 IWineD3DDeviceImpl_SetSamplerState,
6914 IWineD3DDeviceImpl_GetSamplerState,
6915 IWineD3DDeviceImpl_SetScissorRect,
6916 IWineD3DDeviceImpl_GetScissorRect,
6917 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6918 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6919 IWineD3DDeviceImpl_SetStreamSource,
6920 IWineD3DDeviceImpl_GetStreamSource,
6921 IWineD3DDeviceImpl_SetStreamSourceFreq,
6922 IWineD3DDeviceImpl_GetStreamSourceFreq,
6923 IWineD3DDeviceImpl_SetTexture,
6924 IWineD3DDeviceImpl_GetTexture,
6925 IWineD3DDeviceImpl_SetTextureStageState,
6926 IWineD3DDeviceImpl_GetTextureStageState,
6927 IWineD3DDeviceImpl_SetTransform,
6928 IWineD3DDeviceImpl_GetTransform,
6929 IWineD3DDeviceImpl_SetVertexDeclaration,
6930 IWineD3DDeviceImpl_GetVertexDeclaration,
6931 IWineD3DDeviceImpl_SetVertexShader,
6932 IWineD3DDeviceImpl_GetVertexShader,
6933 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6934 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6935 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6936 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6939 IWineD3DDeviceImpl_SetViewport,
6940 IWineD3DDeviceImpl_GetViewport,
6941 IWineD3DDeviceImpl_MultiplyTransform,
6942 IWineD3DDeviceImpl_ValidateDevice,
6943 IWineD3DDeviceImpl_ProcessVertices,
6944 /*** State block ***/
6945 IWineD3DDeviceImpl_BeginStateBlock,
6946 IWineD3DDeviceImpl_EndStateBlock,
6947 /*** Scene management ***/
6948 IWineD3DDeviceImpl_BeginScene,
6949 IWineD3DDeviceImpl_EndScene,
6950 IWineD3DDeviceImpl_Present,
6951 IWineD3DDeviceImpl_Clear,
6952 IWineD3DDeviceImpl_ClearRendertargetView,
6953 /*** Drawing ***/
6954 IWineD3DDeviceImpl_SetPrimitiveType,
6955 IWineD3DDeviceImpl_GetPrimitiveType,
6956 IWineD3DDeviceImpl_DrawPrimitive,
6957 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6958 IWineD3DDeviceImpl_DrawPrimitiveUP,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6960 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6962 IWineD3DDeviceImpl_DrawRectPatch,
6963 IWineD3DDeviceImpl_DrawTriPatch,
6964 IWineD3DDeviceImpl_DeletePatch,
6965 IWineD3DDeviceImpl_ColorFill,
6966 IWineD3DDeviceImpl_UpdateTexture,
6967 IWineD3DDeviceImpl_UpdateSurface,
6968 IWineD3DDeviceImpl_GetFrontBufferData,
6969 /*** object tracking ***/
6970 IWineD3DDeviceImpl_EnumResources,
6971 IWineD3DDeviceImpl_GetSurfaceFromDC,
6972 IWineD3DDeviceImpl_AcquireFocusWindow,
6973 IWineD3DDeviceImpl_ReleaseFocusWindow,
6974 IWineD3DDeviceImpl_SetupFullscreenWindow,
6975 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6978 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6979 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6980 IWineD3DDeviceParent *device_parent)
6982 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6983 const struct fragment_pipeline *fragment_pipeline;
6984 struct shader_caps shader_caps;
6985 struct fragment_caps ffp_caps;
6986 WINED3DDISPLAYMODE mode;
6987 unsigned int i;
6988 HRESULT hr;
6990 device->lpVtbl = &IWineD3DDevice_Vtbl;
6991 device->ref = 1;
6992 device->wined3d = wined3d;
6993 wined3d_incref(device->wined3d);
6994 device->adapter = wined3d->adapter_count ? adapter : NULL;
6995 device->device_parent = device_parent;
6996 list_init(&device->resources);
6997 list_init(&device->shaders);
6999 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7001 /* Get the initial screen setup for ddraw. */
7002 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
7003 if (FAILED(hr))
7005 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7006 wined3d_decref(device->wined3d);
7007 return hr;
7009 device->ddraw_width = mode.Width;
7010 device->ddraw_height = mode.Height;
7011 device->ddraw_format = mode.Format;
7013 /* Save the creation parameters. */
7014 device->createParms.AdapterOrdinal = adapter_idx;
7015 device->createParms.DeviceType = device_type;
7016 device->createParms.hFocusWindow = focus_window;
7017 device->createParms.BehaviorFlags = flags;
7019 device->devType = device_type;
7020 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7022 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7023 device->shader_backend = adapter->shader_backend;
7025 if (device->shader_backend)
7027 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7028 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7029 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7030 device->vs_clipping = shader_caps.VSClipping;
7032 fragment_pipeline = adapter->fragment_pipe;
7033 device->frag_pipe = fragment_pipeline;
7034 if (fragment_pipeline)
7036 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7037 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7039 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7040 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7041 if (FAILED(hr))
7043 ERR("Failed to compile state table, hr %#x.\n", hr);
7044 wined3d_decref(device->wined3d);
7045 return hr;
7048 device->blitter = adapter->blitter;
7050 return WINED3D_OK;
7054 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7055 DWORD rep = This->StateTable[state].representative;
7056 struct wined3d_context *context;
7057 DWORD idx;
7058 BYTE shift;
7059 UINT i;
7061 for(i = 0; i < This->numContexts; i++) {
7062 context = This->contexts[i];
7063 if(isStateDirty(context, rep)) continue;
7065 context->dirtyArray[context->numDirtyEntries++] = rep;
7066 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7067 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7068 context->isStateDirty[idx] |= (1 << shift);
7072 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7074 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7075 *width = context->current_rt->pow2Width;
7076 *height = context->current_rt->pow2Height;
7079 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7081 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7082 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7083 * current context's drawable, which is the size of the back buffer of the swapchain
7084 * the active context belongs to. */
7085 *width = swapchain->presentParms.BackBufferWidth;
7086 *height = swapchain->presentParms.BackBufferHeight;
7089 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7090 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7092 if (device->filter_messages)
7094 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7095 window, message, wparam, lparam);
7096 if (unicode)
7097 return DefWindowProcW(window, message, wparam, lparam);
7098 else
7099 return DefWindowProcA(window, message, wparam, lparam);
7102 if (message == WM_DESTROY)
7104 TRACE("unregister window %p.\n", window);
7105 wined3d_unregister_window(window);
7107 if (device->focus_window == window) device->focus_window = NULL;
7108 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7111 if (unicode)
7112 return CallWindowProcW(proc, window, message, wparam, lparam);
7113 else
7114 return CallWindowProcA(proc, window, message, wparam, lparam);