wined3d: Get rid of the IWineD3DVertexDeclaration typedefs.
[wine.git] / dlls / wined3d / device.c
blob4a1aa62ab269dee2967f284cb1fc27909218ad32
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 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)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->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.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->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.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 IWineD3DResourceImpl *resource;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
873 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
875 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource, debug_d3dresourcetype(type), type);
881 if(This->contexts) ERR("Context array not freed!\n");
882 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
883 This->haveHardwareCursor = FALSE;
885 wined3d_decref(This->wined3d);
886 This->wined3d = NULL;
887 HeapFree(GetProcessHeap(), 0, This);
888 TRACE("Freed device %p\n", This);
889 This = NULL;
891 return refCount;
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
895 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 struct wined3d_buffer *object;
899 HRESULT hr;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
904 if (!object)
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY;
910 FIXME("Ignoring access flags (pool)\n");
912 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
913 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
914 if (FAILED(hr))
916 WARN("Failed to initialize buffer, hr %#x.\n", hr);
917 HeapFree(GetProcessHeap(), 0, object);
918 return hr;
920 object->desc = *desc;
922 TRACE("Created buffer %p.\n", object);
924 *buffer = (IWineD3DBuffer *)object;
926 return WINED3D_OK;
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
930 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
931 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 struct wined3d_buffer *object;
935 HRESULT hr;
937 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
938 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
940 if (Pool == WINED3DPOOL_SCRATCH)
942 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
943 * anyway, SCRATCH vertex buffers aren't usable anywhere
945 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 *ppVertexBuffer = NULL;
947 return WINED3DERR_INVALIDCALL;
950 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
951 if (!object)
953 ERR("Out of memory\n");
954 *ppVertexBuffer = NULL;
955 return WINED3DERR_OUTOFVIDEOMEMORY;
958 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
959 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
960 if (FAILED(hr))
962 WARN("Failed to initialize buffer, hr %#x.\n", hr);
963 HeapFree(GetProcessHeap(), 0, object);
964 return hr;
967 TRACE("Created buffer %p.\n", object);
968 *ppVertexBuffer = (IWineD3DBuffer *)object;
970 return WINED3D_OK;
973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
974 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
975 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
978 struct wined3d_buffer *object;
979 HRESULT hr;
981 TRACE("(%p) Creating index buffer\n", This);
983 /* Allocate the storage for the device */
984 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
985 if (!object)
987 ERR("Out of memory\n");
988 *ppIndexBuffer = NULL;
989 return WINED3DERR_OUTOFVIDEOMEMORY;
992 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
993 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
994 parent, parent_ops);
995 if (FAILED(hr))
997 WARN("Failed to initialize buffer, hr %#x\n", hr);
998 HeapFree(GetProcessHeap(), 0, object);
999 return hr;
1002 TRACE("Created buffer %p.\n", object);
1004 *ppIndexBuffer = (IWineD3DBuffer *) object;
1006 return WINED3D_OK;
1009 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1010 WINED3DSTATEBLOCKTYPE type, struct wined3d_stateblock **stateblock)
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 struct wined3d_stateblock *object;
1014 HRESULT hr;
1016 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1017 if(!object)
1019 ERR("Failed to allocate stateblock memory.\n");
1020 return E_OUTOFMEMORY;
1023 hr = stateblock_init(object, This, type);
1024 if (FAILED(hr))
1026 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1027 HeapFree(GetProcessHeap(), 0, object);
1028 return hr;
1031 TRACE("Created stateblock %p.\n", object);
1032 *stateblock = object;
1034 return WINED3D_OK;
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1038 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1039 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1040 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1043 IWineD3DSurfaceImpl *object;
1044 HRESULT hr;
1046 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1047 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1048 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1049 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1050 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1052 if (Impl == SURFACE_OPENGL && !This->adapter)
1054 ERR("OpenGL surfaces are not available without OpenGL.\n");
1055 return WINED3DERR_NOTAVAILABLE;
1058 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1059 if (!object)
1061 ERR("Failed to allocate surface memory.\n");
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1066 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1067 if (FAILED(hr))
1069 WARN("Failed to initialize surface, returning %#x.\n", hr);
1070 HeapFree(GetProcessHeap(), 0, object);
1071 return hr;
1074 TRACE("(%p) : Created surface %p\n", This, object);
1076 *surface = (IWineD3DSurface *)object;
1078 return hr;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1082 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1084 struct wined3d_rendertarget_view *object;
1086 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1087 iface, resource, parent, rendertarget_view);
1089 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1090 if (!object)
1092 ERR("Failed to allocate memory\n");
1093 return E_OUTOFMEMORY;
1096 wined3d_rendertarget_view_init(object, (IWineD3DResourceImpl *)resource, parent);
1098 TRACE("Created render target view %p.\n", object);
1099 *rendertarget_view = (IWineD3DRendertargetView *)object;
1101 return WINED3D_OK;
1104 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1105 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1106 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1109 IWineD3DTextureImpl *object;
1110 HRESULT hr;
1112 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1113 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1114 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1116 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1117 if (!object)
1119 ERR("Out of memory\n");
1120 *ppTexture = NULL;
1121 return WINED3DERR_OUTOFVIDEOMEMORY;
1124 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1125 if (FAILED(hr))
1127 WARN("Failed to initialize texture, returning %#x\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1129 *ppTexture = NULL;
1130 return hr;
1133 *ppTexture = (IWineD3DTexture *)object;
1135 TRACE("(%p) : Created texture %p\n", This, object);
1137 return WINED3D_OK;
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1141 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1142 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1145 IWineD3DVolumeTextureImpl *object;
1146 HRESULT hr;
1148 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1149 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1151 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1152 if (!object)
1154 ERR("Out of memory\n");
1155 *ppVolumeTexture = NULL;
1156 return WINED3DERR_OUTOFVIDEOMEMORY;
1159 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1160 if (FAILED(hr))
1162 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1163 HeapFree(GetProcessHeap(), 0, object);
1164 *ppVolumeTexture = NULL;
1165 return hr;
1168 TRACE("(%p) : Created volume texture %p.\n", This, object);
1169 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1171 return WINED3D_OK;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1175 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1176 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 IWineD3DVolumeImpl *object;
1180 HRESULT hr;
1182 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1183 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1185 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1186 if (!object)
1188 ERR("Out of memory\n");
1189 *ppVolume = NULL;
1190 return WINED3DERR_OUTOFVIDEOMEMORY;
1193 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1194 if (FAILED(hr))
1196 WARN("Failed to initialize volume, returning %#x.\n", hr);
1197 HeapFree(GetProcessHeap(), 0, object);
1198 return hr;
1201 TRACE("(%p) : Created volume %p.\n", This, object);
1202 *ppVolume = (IWineD3DVolume *)object;
1204 return WINED3D_OK;
1207 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1208 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1209 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1212 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1213 HRESULT hr;
1215 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1216 if (!object)
1218 ERR("Out of memory\n");
1219 *ppCubeTexture = NULL;
1220 return WINED3DERR_OUTOFVIDEOMEMORY;
1223 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1224 if (FAILED(hr))
1226 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1227 HeapFree(GetProcessHeap(), 0, object);
1228 *ppCubeTexture = NULL;
1229 return hr;
1232 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1233 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1235 return WINED3D_OK;
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1239 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1242 IWineD3DQueryImpl *object;
1243 HRESULT hr;
1245 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1247 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1248 if (!object)
1250 ERR("Failed to allocate query memory.\n");
1251 return E_OUTOFMEMORY;
1254 hr = query_init(object, This, type);
1255 if (FAILED(hr))
1257 WARN("Failed to initialize query, hr %#x.\n", hr);
1258 HeapFree(GetProcessHeap(), 0, object);
1259 return hr;
1262 TRACE("Created query %p.\n", object);
1263 *query = (IWineD3DQuery *)object;
1265 return WINED3D_OK;
1268 /* Do not call while under the GL lock. */
1269 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1270 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1271 void *parent, IWineD3DSwapChain **swapchain)
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DSwapChainImpl *object;
1275 HRESULT hr;
1277 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1278 iface, present_parameters, swapchain, parent, surface_type);
1280 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1281 if (!object)
1283 ERR("Failed to allocate swapchain memory.\n");
1284 return E_OUTOFMEMORY;
1287 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1288 if (FAILED(hr))
1290 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1291 HeapFree(GetProcessHeap(), 0, object);
1292 return hr;
1295 TRACE("Created swapchain %p.\n", object);
1296 *swapchain = (IWineD3DSwapChain *)object;
1298 return WINED3D_OK;
1301 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1302 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 TRACE("(%p)\n", This);
1306 return This->NumberOfSwapChains;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1311 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1313 if (iSwapChain < This->NumberOfSwapChains)
1315 *pSwapChain = (IWineD3DSwapChain *)This->swapchains[iSwapChain];
1316 IWineD3DSwapChain_AddRef(*pSwapChain);
1317 TRACE("(%p) returning %p\n", This, *pSwapChain);
1318 return WINED3D_OK;
1319 } else {
1320 TRACE("Swapchain out of range\n");
1321 *pSwapChain = NULL;
1322 return WINED3DERR_INVALIDCALL;
1326 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1327 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1328 const struct wined3d_parent_ops *parent_ops, struct wined3d_vertex_declaration **declaration)
1330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1331 struct wined3d_vertex_declaration *object;
1332 HRESULT hr;
1334 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1335 iface, elements, element_count, parent, parent_ops, declaration);
1337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1338 if(!object)
1340 ERR("Failed to allocate vertex declaration memory.\n");
1341 return E_OUTOFMEMORY;
1344 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1345 if (FAILED(hr))
1347 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1348 HeapFree(GetProcessHeap(), 0, object);
1349 return hr;
1352 TRACE("Created vertex declaration %p.\n", object);
1353 *declaration = object;
1355 return WINED3D_OK;
1358 struct wined3d_fvf_convert_state
1360 const struct wined3d_gl_info *gl_info;
1361 WINED3DVERTEXELEMENT *elements;
1362 UINT offset;
1363 UINT idx;
1366 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1367 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1369 WINED3DVERTEXELEMENT *elements = state->elements;
1370 const struct wined3d_format *format;
1371 UINT offset = state->offset;
1372 UINT idx = state->idx;
1374 elements[idx].format = format_id;
1375 elements[idx].input_slot = 0;
1376 elements[idx].offset = offset;
1377 elements[idx].output_slot = 0;
1378 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1379 elements[idx].usage = usage;
1380 elements[idx].usage_idx = usage_idx;
1382 format = wined3d_get_format(state->gl_info, format_id);
1383 state->offset += format->component_count * format->component_size;
1384 ++state->idx;
1387 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1388 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1390 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1391 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1392 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1393 BOOL has_blend_idx = has_blend &&
1394 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1395 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1396 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1397 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1398 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1399 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1400 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1402 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1403 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1404 struct wined3d_fvf_convert_state state;
1405 unsigned int size;
1406 unsigned int idx;
1407 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1408 if (has_blend_idx) num_blends--;
1410 /* Compute declaration size */
1411 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1412 has_psize + has_diffuse + has_specular + num_textures;
1414 state.gl_info = gl_info;
1415 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1416 if (!state.elements) return ~0U;
1417 state.offset = 0;
1418 state.idx = 0;
1420 if (has_pos)
1422 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1423 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1424 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1425 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1426 else
1427 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1430 if (has_blend && (num_blends > 0))
1432 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1433 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 else
1436 switch (num_blends)
1438 case 1:
1439 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 break;
1441 case 2:
1442 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 case 3:
1445 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 break;
1447 case 4:
1448 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 break;
1450 default:
1451 ERR("Unexpected amount of blend values: %u\n", num_blends);
1456 if (has_blend_idx)
1458 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1459 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1460 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1462 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1463 else
1464 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1467 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1468 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1469 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1470 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1472 for (idx = 0; idx < num_textures; ++idx)
1474 switch ((texcoords >> (idx * 2)) & 0x03)
1476 case WINED3DFVF_TEXTUREFORMAT1:
1477 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 break;
1479 case WINED3DFVF_TEXTUREFORMAT2:
1480 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1482 case WINED3DFVF_TEXTUREFORMAT3:
1483 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1484 break;
1485 case WINED3DFVF_TEXTUREFORMAT4:
1486 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1487 break;
1491 *ppVertexElements = state.elements;
1492 return size;
1495 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1496 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1497 struct wined3d_vertex_declaration **declaration)
1499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1500 WINED3DVERTEXELEMENT *elements;
1501 unsigned int size;
1502 DWORD hr;
1504 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1505 iface, fvf, parent, parent_ops, declaration);
1507 size = ConvertFvfToDeclaration(This, fvf, &elements);
1508 if (size == ~0U) return E_OUTOFMEMORY;
1510 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1511 HeapFree(GetProcessHeap(), 0, elements);
1512 return hr;
1515 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1516 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1517 void *parent, const struct wined3d_parent_ops *parent_ops,
1518 IWineD3DVertexShader **ppVertexShader)
1520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1521 IWineD3DVertexShaderImpl *object;
1522 HRESULT hr;
1524 if (This->vs_selected_mode == SHADER_NONE)
1525 return WINED3DERR_INVALIDCALL;
1527 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1528 if (!object)
1530 ERR("Failed to allocate shader memory.\n");
1531 return E_OUTOFMEMORY;
1534 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1535 if (FAILED(hr))
1537 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1538 HeapFree(GetProcessHeap(), 0, object);
1539 return hr;
1542 TRACE("Created vertex shader %p.\n", object);
1543 *ppVertexShader = (IWineD3DVertexShader *)object;
1545 return WINED3D_OK;
1548 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1549 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1550 void *parent, const struct wined3d_parent_ops *parent_ops,
1551 IWineD3DGeometryShader **shader)
1553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 struct wined3d_geometryshader *object;
1555 HRESULT hr;
1557 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1558 if (!object)
1560 ERR("Failed to allocate shader memory.\n");
1561 return E_OUTOFMEMORY;
1564 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1565 if (FAILED(hr))
1567 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1568 HeapFree(GetProcessHeap(), 0, object);
1569 return hr;
1572 TRACE("Created geometry shader %p.\n", object);
1573 *shader = (IWineD3DGeometryShader *)object;
1575 return WINED3D_OK;
1578 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1579 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1580 void *parent, const struct wined3d_parent_ops *parent_ops,
1581 IWineD3DPixelShader **ppPixelShader)
1583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1584 IWineD3DPixelShaderImpl *object;
1585 HRESULT hr;
1587 if (This->ps_selected_mode == SHADER_NONE)
1588 return WINED3DERR_INVALIDCALL;
1590 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1591 if (!object)
1593 ERR("Failed to allocate shader memory.\n");
1594 return E_OUTOFMEMORY;
1597 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1598 if (FAILED(hr))
1600 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1601 HeapFree(GetProcessHeap(), 0, object);
1602 return hr;
1605 TRACE("Created pixel shader %p.\n", object);
1606 *ppPixelShader = (IWineD3DPixelShader *)object;
1608 return WINED3D_OK;
1611 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1612 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1615 IWineD3DPaletteImpl *object;
1616 HRESULT hr;
1618 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1619 iface, flags, PalEnt, Palette, parent);
1621 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1622 if (!object)
1624 ERR("Failed to allocate palette memory.\n");
1625 return E_OUTOFMEMORY;
1628 hr = wined3d_palette_init(object, This, flags, PalEnt, parent);
1629 if (FAILED(hr))
1631 WARN("Failed to initialize palette, hr %#x.\n", hr);
1632 HeapFree(GetProcessHeap(), 0, object);
1633 return hr;
1636 TRACE("Created palette %p.\n", object);
1637 *Palette = (IWineD3DPalette *)object;
1639 return WINED3D_OK;
1642 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1643 HBITMAP hbm;
1644 BITMAP bm;
1645 HRESULT hr;
1646 HDC dcb = NULL, dcs = NULL;
1647 WINEDDCOLORKEY colorkey;
1649 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1650 if(hbm)
1652 GetObjectA(hbm, sizeof(BITMAP), &bm);
1653 dcb = CreateCompatibleDC(NULL);
1654 if(!dcb) goto out;
1655 SelectObject(dcb, hbm);
1657 else
1659 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1660 * couldn't be loaded
1662 memset(&bm, 0, sizeof(bm));
1663 bm.bmWidth = 32;
1664 bm.bmHeight = 32;
1667 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1668 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1669 &wined3d_null_parent_ops, &This->logo_surface);
1670 if (FAILED(hr))
1672 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1673 goto out;
1676 if(dcb) {
1677 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1678 if(FAILED(hr)) goto out;
1679 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1680 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1682 colorkey.dwColorSpaceLowValue = 0;
1683 colorkey.dwColorSpaceHighValue = 0;
1684 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1686 else
1688 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1689 /* Fill the surface with a white color to show that wined3d is there */
1690 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1693 out:
1694 if (dcb) DeleteDC(dcb);
1695 if (hbm) DeleteObject(hbm);
1698 /* Context activation is done by the caller. */
1699 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1701 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1702 unsigned int i;
1703 /* Under DirectX you can have texture stage operations even if no texture is
1704 bound, whereas opengl will only do texture operations when a valid texture is
1705 bound. We emulate this by creating dummy textures and binding them to each
1706 texture stage, but disable all stages by default. Hence if a stage is enabled
1707 then the default texture will kick in until replaced by a SetTexture call */
1708 ENTER_GL();
1710 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1712 /* The dummy texture does not have client storage backing */
1713 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1714 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1717 for (i = 0; i < gl_info->limits.textures; ++i)
1719 GLubyte white = 255;
1721 /* Make appropriate texture active */
1722 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1723 checkGLcall("glActiveTextureARB");
1725 /* Generate an opengl texture name */
1726 glGenTextures(1, &This->dummyTextureName[i]);
1727 checkGLcall("glGenTextures");
1728 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1730 /* Generate a dummy 2d texture (not using 1d because they cause many
1731 * DRI drivers fall back to sw) */
1732 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1733 checkGLcall("glBindTexture");
1735 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1736 checkGLcall("glTexImage2D");
1739 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1741 /* Reenable because if supported it is enabled by default */
1742 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1743 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1746 LEAVE_GL();
1749 /* Context activation is done by the caller. */
1750 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1752 ENTER_GL();
1753 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1754 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1755 LEAVE_GL();
1757 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1760 static LONG fullscreen_style(LONG style)
1762 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1763 style |= WS_POPUP | WS_SYSMENU;
1764 style &= ~(WS_CAPTION | WS_THICKFRAME);
1766 return style;
1769 static LONG fullscreen_exstyle(LONG exstyle)
1771 /* Filter out window decorations. */
1772 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1774 return exstyle;
1777 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1779 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1780 BOOL filter_messages;
1781 LONG style, exstyle;
1783 TRACE("Setting up window %p for fullscreen mode.\n", window);
1785 if (device->style || device->exStyle)
1787 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1788 window, device->style, device->exStyle);
1791 device->style = GetWindowLongW(window, GWL_STYLE);
1792 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1794 style = fullscreen_style(device->style);
1795 exstyle = fullscreen_exstyle(device->exStyle);
1797 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1798 device->style, device->exStyle, style, exstyle);
1800 filter_messages = device->filter_messages;
1801 device->filter_messages = TRUE;
1803 SetWindowLongW(window, GWL_STYLE, style);
1804 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1805 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1807 device->filter_messages = filter_messages;
1810 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1812 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1813 BOOL filter_messages;
1814 LONG style, exstyle;
1816 if (!device->style && !device->exStyle) return;
1818 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1819 window, device->style, device->exStyle);
1821 style = GetWindowLongW(window, GWL_STYLE);
1822 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1824 filter_messages = device->filter_messages;
1825 device->filter_messages = TRUE;
1827 /* Only restore the style if the application didn't modify it during the
1828 * fullscreen phase. Some applications change it before calling Reset()
1829 * when switching between windowed and fullscreen modes (HL2), some
1830 * depend on the original style (Eve Online). */
1831 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1833 SetWindowLongW(window, GWL_STYLE, device->style);
1834 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1836 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1838 device->filter_messages = filter_messages;
1840 /* Delete the old values. */
1841 device->style = 0;
1842 device->exStyle = 0;
1845 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1847 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1849 TRACE("iface %p, window %p.\n", iface, window);
1851 if (!wined3d_register_window(window, device))
1853 ERR("Failed to register window %p.\n", window);
1854 return E_FAIL;
1857 device->focus_window = window;
1858 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1860 return WINED3D_OK;
1863 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1865 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1867 TRACE("iface %p.\n", iface);
1869 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1870 device->focus_window = NULL;
1873 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1874 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1877 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1878 IWineD3DSwapChainImpl *swapchain = NULL;
1879 struct wined3d_context *context;
1880 HRESULT hr;
1881 DWORD state;
1882 unsigned int i;
1884 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1886 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1887 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1889 TRACE("(%p) : Creating stateblock\n", This);
1890 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
1891 if (FAILED(hr))
1893 WARN("Failed to create stateblock\n");
1894 goto err_out;
1896 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1897 This->updateStateBlock = This->stateBlock;
1898 wined3d_stateblock_incref(This->updateStateBlock);
1900 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1901 sizeof(*This->render_targets) * gl_info->limits.buffers);
1903 This->NumberOfPalettes = 1;
1904 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1905 if (!This->palettes || !This->render_targets)
1907 ERR("Out of memory!\n");
1908 hr = E_OUTOFMEMORY;
1909 goto err_out;
1911 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1912 if(!This->palettes[0]) {
1913 ERR("Out of memory!\n");
1914 hr = E_OUTOFMEMORY;
1915 goto err_out;
1917 for (i = 0; i < 256; ++i) {
1918 This->palettes[0][i].peRed = 0xFF;
1919 This->palettes[0][i].peGreen = 0xFF;
1920 This->palettes[0][i].peBlue = 0xFF;
1921 This->palettes[0][i].peFlags = 0xFF;
1923 This->currentPalette = 0;
1925 /* Initialize the texture unit mapping to a 1:1 mapping */
1926 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1928 if (state < gl_info->limits.fragment_samplers)
1930 This->texUnitMap[state] = state;
1931 This->rev_tex_unit_map[state] = state;
1932 } else {
1933 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1934 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1938 /* Setup the implicit swapchain. This also initializes a context. */
1939 TRACE("Creating implicit swapchain\n");
1940 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1941 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1942 if (FAILED(hr))
1944 WARN("Failed to create implicit swapchain\n");
1945 goto err_out;
1948 This->NumberOfSwapChains = 1;
1949 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
1950 if (!This->swapchains)
1952 ERR("Out of memory!\n");
1953 goto err_out;
1955 This->swapchains[0] = swapchain;
1957 if (swapchain->back_buffers && swapchain->back_buffers[0])
1959 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1960 This->render_targets[0] = swapchain->back_buffers[0];
1962 else
1964 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1965 This->render_targets[0] = swapchain->front_buffer;
1967 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1969 /* Depth Stencil support */
1970 This->depth_stencil = This->auto_depth_stencil;
1971 if (This->depth_stencil)
1972 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1974 hr = This->shader_backend->shader_alloc_private(This);
1975 if(FAILED(hr)) {
1976 TRACE("Shader private data couldn't be allocated\n");
1977 goto err_out;
1979 hr = This->frag_pipe->alloc_private(This);
1980 if(FAILED(hr)) {
1981 TRACE("Fragment pipeline private data couldn't be allocated\n");
1982 goto err_out;
1984 hr = This->blitter->alloc_private(This);
1985 if(FAILED(hr)) {
1986 TRACE("Blitter private data couldn't be allocated\n");
1987 goto err_out;
1990 /* Set up some starting GL setup */
1992 /* Setup all the devices defaults */
1993 stateblock_init_default_state(This->stateBlock);
1995 context = context_acquire(This, swapchain->front_buffer);
1997 create_dummy_textures(This);
1999 ENTER_GL();
2001 /* Initialize the current view state */
2002 This->view_ident = 1;
2003 This->contexts[0]->last_was_rhw = 0;
2004 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2005 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2007 switch(wined3d_settings.offscreen_rendering_mode) {
2008 case ORM_FBO:
2009 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2010 break;
2012 case ORM_BACKBUFFER:
2014 if (context_get_current()->aux_buffers > 0)
2016 TRACE("Using auxilliary buffer for offscreen rendering\n");
2017 This->offscreenBuffer = GL_AUX0;
2018 } else {
2019 TRACE("Using back buffer for offscreen rendering\n");
2020 This->offscreenBuffer = GL_BACK;
2025 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2026 LEAVE_GL();
2028 context_release(context);
2030 /* Clear the screen */
2031 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2032 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2033 0x00, 1.0f, 0);
2035 This->d3d_initialized = TRUE;
2037 if(wined3d_settings.logo) {
2038 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2040 This->highest_dirty_ps_const = 0;
2041 This->highest_dirty_vs_const = 0;
2042 return WINED3D_OK;
2044 err_out:
2045 HeapFree(GetProcessHeap(), 0, This->render_targets);
2046 HeapFree(GetProcessHeap(), 0, This->swapchains);
2047 This->NumberOfSwapChains = 0;
2048 if(This->palettes) {
2049 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2050 HeapFree(GetProcessHeap(), 0, This->palettes);
2052 This->NumberOfPalettes = 0;
2053 if(swapchain) {
2054 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2056 if (This->stateBlock)
2058 wined3d_stateblock_decref(This->stateBlock);
2059 This->stateBlock = NULL;
2061 if (This->blit_priv) {
2062 This->blitter->free_private(This);
2064 if (This->fragment_priv) {
2065 This->frag_pipe->free_private(This);
2067 if (This->shader_priv) {
2068 This->shader_backend->shader_free_private(This);
2070 return hr;
2073 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2074 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2077 IWineD3DSwapChainImpl *swapchain = NULL;
2078 HRESULT hr;
2080 /* Setup the implicit swapchain */
2081 TRACE("Creating implicit swapchain\n");
2082 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2083 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 if (FAILED(hr))
2086 WARN("Failed to create implicit swapchain\n");
2087 goto err_out;
2090 This->NumberOfSwapChains = 1;
2091 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(*This->swapchains));
2092 if (!This->swapchains)
2094 ERR("Out of memory!\n");
2095 goto err_out;
2097 This->swapchains[0] = swapchain;
2098 return WINED3D_OK;
2100 err_out:
2101 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2102 return hr;
2105 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2107 IWineD3DResource_UnLoad(resource);
2108 IWineD3DResource_Release(resource);
2109 return WINED3D_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 /*****
2388 * Get / Set Stream Source
2389 *****/
2390 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2391 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 struct wined3d_stream_state *stream;
2395 IWineD3DBuffer *oldSrc;
2397 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2398 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2400 if (StreamNumber >= MAX_STREAMS) {
2401 WARN("Stream out of range %d\n", StreamNumber);
2402 return WINED3DERR_INVALIDCALL;
2403 } else if(OffsetInBytes & 0x3) {
2404 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2405 return WINED3DERR_INVALIDCALL;
2408 stream = &This->updateStateBlock->state.streams[StreamNumber];
2409 oldSrc = (IWineD3DBuffer *)stream->buffer;
2411 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2413 if (oldSrc == pStreamData
2414 && stream->stride == Stride
2415 && stream->offset == OffsetInBytes)
2417 TRACE("Application is setting the old values over, nothing to do\n");
2418 return WINED3D_OK;
2421 stream->buffer = (struct wined3d_buffer *)pStreamData;
2422 if (pStreamData)
2424 stream->stride = Stride;
2425 stream->offset = OffsetInBytes;
2428 /* Handle recording of state blocks */
2429 if (This->isRecordingState) {
2430 TRACE("Recording... not performing anything\n");
2431 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2432 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2433 return WINED3D_OK;
2436 if (pStreamData)
2438 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2439 IWineD3DBuffer_AddRef(pStreamData);
2441 if (oldSrc)
2443 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2444 IWineD3DBuffer_Release(oldSrc);
2447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2449 return WINED3D_OK;
2452 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2453 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2456 struct wined3d_stream_state *stream;
2458 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2459 iface, StreamNumber, pStream, pOffset, pStride);
2461 if (StreamNumber >= MAX_STREAMS)
2463 WARN("Stream out of range %d\n", StreamNumber);
2464 return WINED3DERR_INVALIDCALL;
2467 stream = &This->stateBlock->state.streams[StreamNumber];
2468 *pStream = (IWineD3DBuffer *)stream->buffer;
2469 *pStride = stream->stride;
2470 if (pOffset) *pOffset = stream->offset;
2472 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
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 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 IWineD3DBuffer *oldIdxs;
3052 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3053 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3055 This->updateStateBlock->changed.indices = TRUE;
3056 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3057 This->updateStateBlock->state.index_format = fmt;
3059 /* Handle recording of state blocks */
3060 if (This->isRecordingState) {
3061 TRACE("Recording... not performing anything\n");
3062 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3063 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3064 return WINED3D_OK;
3067 if(oldIdxs != pIndexData) {
3068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3069 if(pIndexData) {
3070 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3071 IWineD3DBuffer_AddRef(pIndexData);
3073 if(oldIdxs) {
3074 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3075 IWineD3DBuffer_Release(oldIdxs);
3079 return WINED3D_OK;
3082 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3088 /* up ref count on ppindexdata */
3089 if (*ppIndexData) {
3090 IWineD3DBuffer_AddRef(*ppIndexData);
3091 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3092 }else{
3093 TRACE("(%p) No index data set\n", This);
3095 TRACE("Returning %p\n", *ppIndexData);
3097 return WINED3D_OK;
3100 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3101 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p)->(%d)\n", This, BaseIndex);
3105 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3107 TRACE("Application is setting the old value over, nothing to do\n");
3108 return WINED3D_OK;
3111 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3113 if (This->isRecordingState) {
3114 TRACE("Recording... not performing anything\n");
3115 return WINED3D_OK;
3117 /* The base vertex index affects the stream sources */
3118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3119 return WINED3D_OK;
3122 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 TRACE("(%p) : base_index %p\n", This, base_index);
3126 *base_index = This->stateBlock->state.base_vertex_index;
3128 TRACE("Returning %u\n", *base_index);
3130 return WINED3D_OK;
3133 /*****
3134 * Get / Set Viewports
3135 *****/
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 TRACE("(%p)\n", This);
3140 This->updateStateBlock->changed.viewport = TRUE;
3141 This->updateStateBlock->state.viewport = *pViewport;
3143 /* Handle recording of state blocks */
3144 if (This->isRecordingState) {
3145 TRACE("Recording... not performing anything\n");
3146 return WINED3D_OK;
3149 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3150 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3153 return WINED3D_OK;
3157 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 TRACE("(%p)\n", This);
3160 *pViewport = This->stateBlock->state.viewport;
3161 return WINED3D_OK;
3164 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3165 WINED3DRENDERSTATETYPE State, DWORD Value)
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 DWORD oldValue = This->stateBlock->state.render_states[State];
3170 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3172 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3173 This->updateStateBlock->state.render_states[State] = Value;
3175 /* Handle recording of state blocks */
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3178 return WINED3D_OK;
3181 /* Compared here and not before the assignment to allow proper stateblock recording */
3182 if(Value == oldValue) {
3183 TRACE("Application is setting the old value over, nothing to do\n");
3184 } else {
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3192 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3196 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3198 *pValue = This->stateBlock->state.render_states[State];
3199 return WINED3D_OK;
3202 /*****
3203 * Get / Set Sampler States
3204 * TODO: Verify against dx9 definitions
3205 *****/
3207 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 DWORD oldValue;
3211 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3212 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3214 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3215 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3218 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3220 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3221 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3224 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3225 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3226 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3228 /* Handle recording of state blocks */
3229 if (This->isRecordingState) {
3230 TRACE("Recording... not performing anything\n");
3231 return WINED3D_OK;
3234 if(oldValue == Value) {
3235 TRACE("Application is setting the old value over, nothing to do\n");
3236 return WINED3D_OK;
3239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3241 return WINED3D_OK;
3244 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3248 This, Sampler, debug_d3dsamplerstate(Type), Type);
3250 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3251 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3254 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3256 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3257 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3259 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3260 TRACE("(%p) : Returning %#x\n", This, *Value);
3262 return WINED3D_OK;
3265 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 This->updateStateBlock->changed.scissorRect = TRUE;
3269 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3271 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3272 return WINED3D_OK;
3274 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3276 if(This->isRecordingState) {
3277 TRACE("Recording... not performing anything\n");
3278 return WINED3D_OK;
3281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3283 return WINED3D_OK;
3286 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 *pRect = This->updateStateBlock->state.scissor_rect;
3290 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3291 return WINED3D_OK;
3294 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice *iface,
3295 struct wined3d_vertex_declaration *pDecl)
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3298 struct wined3d_vertex_declaration *oldDecl = This->updateStateBlock->state.vertex_declaration;
3300 TRACE("iface %p, declaration %p.\n", iface, pDecl);
3302 if (pDecl)
3303 wined3d_vertex_declaration_incref(pDecl);
3304 if (oldDecl)
3305 wined3d_vertex_declaration_decref(oldDecl);
3307 This->updateStateBlock->state.vertex_declaration = pDecl;
3308 This->updateStateBlock->changed.vertexDecl = TRUE;
3310 if (This->isRecordingState) {
3311 TRACE("Recording... not performing anything\n");
3312 return WINED3D_OK;
3313 } else if(pDecl == oldDecl) {
3314 /* Checked after the assignment to allow proper stateblock recording */
3315 TRACE("Application is setting the old declaration over, nothing to do\n");
3316 return WINED3D_OK;
3319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3320 return WINED3D_OK;
3323 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice *iface,
3324 struct wined3d_vertex_declaration **ppDecl)
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 TRACE("iface %p, declaration %p.\n", iface, ppDecl);
3330 *ppDecl = This->stateBlock->state.vertex_declaration;
3331 if (*ppDecl)
3332 wined3d_vertex_declaration_incref(*ppDecl);
3334 return WINED3D_OK;
3337 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3340 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3342 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3343 This->updateStateBlock->changed.vertexShader = TRUE;
3345 if (This->isRecordingState) {
3346 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3347 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3348 TRACE("Recording... not performing anything\n");
3349 return WINED3D_OK;
3350 } else if(oldShader == pShader) {
3351 /* Checked here to allow proper stateblock recording */
3352 TRACE("App is setting the old shader over, nothing to do\n");
3353 return WINED3D_OK;
3356 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3357 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3358 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3362 return WINED3D_OK;
3365 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3367 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3368 IWineD3DVertexShader *shader;
3370 TRACE("iface %p.\n", iface);
3372 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3373 if (shader) IWineD3DVertexShader_AddRef(shader);
3375 TRACE("Returning %p.\n", shader);
3376 return shader;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3380 IWineD3DDevice *iface,
3381 UINT start,
3382 CONST BOOL *srcData,
3383 UINT count) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3388 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3389 iface, srcData, start, count);
3391 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3393 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3394 for (i = 0; i < cnt; i++)
3395 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3397 for (i = start; i < cnt + start; ++i) {
3398 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3401 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3403 return WINED3D_OK;
3406 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3407 IWineD3DDevice *iface,
3408 UINT start,
3409 BOOL *dstData,
3410 UINT count) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3413 int cnt = min(count, MAX_CONST_B - start);
3415 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3416 iface, dstData, start, count);
3418 if (!dstData || cnt < 0)
3419 return WINED3DERR_INVALIDCALL;
3421 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3426 IWineD3DDevice *iface,
3427 UINT start,
3428 CONST int *srcData,
3429 UINT count) {
3431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3432 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3434 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3435 iface, srcData, start, count);
3437 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3439 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3440 for (i = 0; i < cnt; i++)
3441 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3442 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3444 for (i = start; i < cnt + start; ++i) {
3445 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3448 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3450 return WINED3D_OK;
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3454 IWineD3DDevice *iface,
3455 UINT start,
3456 int *dstData,
3457 UINT count) {
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3460 int cnt = min(count, MAX_CONST_I - start);
3462 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3463 iface, dstData, start, count);
3465 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3466 return WINED3DERR_INVALIDCALL;
3468 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3469 return WINED3D_OK;
3472 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3473 IWineD3DDevice *iface,
3474 UINT start,
3475 CONST float *srcData,
3476 UINT count) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 UINT i;
3481 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3482 iface, srcData, start, count);
3484 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3485 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3486 return WINED3DERR_INVALIDCALL;
3488 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3489 if(TRACE_ON(d3d)) {
3490 for (i = 0; i < count; i++)
3491 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3492 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3495 if (!This->isRecordingState)
3497 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3501 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3502 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3504 return WINED3D_OK;
3507 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3508 IWineD3DDevice *iface,
3509 UINT start,
3510 float *dstData,
3511 UINT count) {
3513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 int cnt = min(count, This->d3d_vshader_constantF - start);
3516 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3517 iface, dstData, start, count);
3519 if (!dstData || cnt < 0)
3520 return WINED3DERR_INVALIDCALL;
3522 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3523 return WINED3D_OK;
3526 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3527 DWORD i;
3528 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3534 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3536 DWORD i = This->rev_tex_unit_map[unit];
3537 DWORD j = This->texUnitMap[stage];
3539 This->texUnitMap[stage] = unit;
3540 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3542 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3545 This->rev_tex_unit_map[unit] = stage;
3546 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3548 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3552 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3553 int i;
3555 This->fixed_function_usage_map = 0;
3556 for (i = 0; i < MAX_TEXTURES; ++i)
3558 const struct wined3d_state *state = &This->stateBlock->state;
3559 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3560 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3561 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3562 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3563 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3564 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3565 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3566 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3568 if (color_op == WINED3DTOP_DISABLE) {
3569 /* Not used, and disable higher stages */
3570 break;
3573 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3574 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3575 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3576 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3577 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3578 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3579 This->fixed_function_usage_map |= (1 << i);
3582 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3583 This->fixed_function_usage_map |= (1 << (i + 1));
3588 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3590 unsigned int i, tex;
3591 WORD ffu_map;
3593 device_update_fixed_function_usage_map(This);
3594 ffu_map = This->fixed_function_usage_map;
3596 if (This->max_ffp_textures == gl_info->limits.texture_stages
3597 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3599 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3601 if (!(ffu_map & 1)) continue;
3603 if (This->texUnitMap[i] != i) {
3604 device_map_stage(This, i, i);
3605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3606 markTextureStagesDirty(This, i);
3609 return;
3612 /* Now work out the mapping */
3613 tex = 0;
3614 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3616 if (!(ffu_map & 1)) continue;
3618 if (This->texUnitMap[i] != tex) {
3619 device_map_stage(This, i, tex);
3620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3621 markTextureStagesDirty(This, i);
3624 ++tex;
3628 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3630 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3631 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3632 unsigned int i;
3634 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3635 if (sampler_type[i] && This->texUnitMap[i] != i)
3637 device_map_stage(This, i, i);
3638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3639 if (i < gl_info->limits.texture_stages)
3641 markTextureStagesDirty(This, i);
3647 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3648 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3650 DWORD current_mapping = This->rev_tex_unit_map[unit];
3652 /* Not currently used */
3653 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3655 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3656 /* Used by a fragment sampler */
3658 if (!pshader_sampler_tokens) {
3659 /* No pixel shader, check fixed function */
3660 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3663 /* Pixel shader, check the shader's sampler map */
3664 return !pshader_sampler_tokens[current_mapping];
3667 /* Used by a vertex sampler */
3668 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3671 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3673 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3674 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3675 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3676 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3677 int i;
3679 if (ps)
3681 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3683 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3684 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3685 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3688 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3689 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3690 if (vshader_sampler_type[i])
3692 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3694 /* Already mapped somewhere */
3695 continue;
3698 while (start >= 0) {
3699 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3701 device_map_stage(This, vsampler_idx, start);
3702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3704 --start;
3705 break;
3708 --start;
3714 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3716 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3717 const struct wined3d_state *state = &This->stateBlock->state;
3718 BOOL vs = use_vs(state);
3719 BOOL ps = use_ps(state);
3721 * Rules are:
3722 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3723 * that would be really messy and require shader recompilation
3724 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3725 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3727 if (ps) device_map_psamplers(This, gl_info);
3728 else device_map_fixed_function_samplers(This, gl_info);
3730 if (vs) device_map_vsamplers(This, ps, gl_info);
3733 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3736 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3737 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3738 This->updateStateBlock->changed.pixelShader = TRUE;
3740 /* Handle recording of state blocks */
3741 if (This->isRecordingState) {
3742 TRACE("Recording... not performing anything\n");
3745 if (This->isRecordingState) {
3746 TRACE("Recording... not performing anything\n");
3747 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3748 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3749 return WINED3D_OK;
3752 if(pShader == oldShader) {
3753 TRACE("App is setting the old pixel shader over, nothing to do\n");
3754 return WINED3D_OK;
3757 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3758 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3760 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3763 return WINED3D_OK;
3766 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3768 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3769 IWineD3DPixelShader *shader;
3771 TRACE("iface %p.\n", iface);
3773 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3774 if (shader) IWineD3DPixelShader_AddRef(shader);
3776 TRACE("Returning %p.\n", shader);
3777 return shader;
3780 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3781 IWineD3DDevice *iface,
3782 UINT start,
3783 CONST BOOL *srcData,
3784 UINT count) {
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3789 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3790 iface, srcData, start, count);
3792 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3794 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3795 for (i = 0; i < cnt; i++)
3796 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3798 for (i = start; i < cnt + start; ++i) {
3799 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3802 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3804 return WINED3D_OK;
3807 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3808 IWineD3DDevice *iface,
3809 UINT start,
3810 BOOL *dstData,
3811 UINT count) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3814 int cnt = min(count, MAX_CONST_B - start);
3816 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3817 iface, dstData, start, count);
3819 if (!dstData || cnt < 0)
3820 return WINED3DERR_INVALIDCALL;
3822 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3823 return WINED3D_OK;
3826 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3827 IWineD3DDevice *iface,
3828 UINT start,
3829 CONST int *srcData,
3830 UINT count) {
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3835 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3836 iface, srcData, start, count);
3838 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3840 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3841 for (i = 0; i < cnt; i++)
3842 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3843 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3845 for (i = start; i < cnt + start; ++i) {
3846 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3849 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3851 return WINED3D_OK;
3854 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3855 IWineD3DDevice *iface,
3856 UINT start,
3857 int *dstData,
3858 UINT count) {
3860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3861 int cnt = min(count, MAX_CONST_I - start);
3863 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3864 iface, dstData, start, count);
3866 if (!dstData || cnt < 0)
3867 return WINED3DERR_INVALIDCALL;
3869 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3870 return WINED3D_OK;
3873 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3874 IWineD3DDevice *iface,
3875 UINT start,
3876 CONST float *srcData,
3877 UINT count) {
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 UINT i;
3882 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3883 iface, srcData, start, count);
3885 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3886 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3890 if(TRACE_ON(d3d)) {
3891 for (i = 0; i < count; i++)
3892 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3893 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3896 if (!This->isRecordingState)
3898 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3902 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3903 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3905 return WINED3D_OK;
3908 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3909 IWineD3DDevice *iface,
3910 UINT start,
3911 float *dstData,
3912 UINT count) {
3914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3915 int cnt = min(count, This->d3d_pshader_constantF - start);
3917 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3918 iface, dstData, start, count);
3920 if (!dstData || cnt < 0)
3921 return WINED3DERR_INVALIDCALL;
3923 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3924 return WINED3D_OK;
3927 /* Context activation is done by the caller. */
3928 /* Do not call while under the GL lock. */
3929 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3930 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3931 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3932 DWORD DestFVF)
3934 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3935 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3936 unsigned int i;
3937 WINED3DVIEWPORT vp;
3938 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3939 BOOL doClip;
3940 DWORD numTextures;
3942 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3944 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3947 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3949 ERR("Source has no position mask\n");
3950 return WINED3DERR_INVALIDCALL;
3953 if (!dest->resource.allocatedMemory)
3954 buffer_get_sysmem(dest, gl_info);
3956 /* Get a pointer into the destination vbo(create one if none exists) and
3957 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3959 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3961 dest->flags |= WINED3D_BUFFER_CREATEBO;
3962 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3965 if (dest->buffer_object)
3967 unsigned char extrabytes = 0;
3968 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3969 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3970 * this may write 4 extra bytes beyond the area that should be written
3972 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3973 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3974 if(!dest_conv_addr) {
3975 ERR("Out of memory\n");
3976 /* Continue without storing converted vertices */
3978 dest_conv = dest_conv_addr;
3981 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3983 static BOOL warned = FALSE;
3985 * The clipping code is not quite correct. Some things need
3986 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3987 * so disable clipping for now.
3988 * (The graphics in Half-Life are broken, and my processvertices
3989 * test crashes with IDirect3DDevice3)
3990 doClip = TRUE;
3992 doClip = FALSE;
3993 if(!warned) {
3994 warned = TRUE;
3995 FIXME("Clipping is broken and disabled for now\n");
3997 } else doClip = FALSE;
3998 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4000 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4001 WINED3DTS_VIEW,
4002 &view_mat);
4003 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4004 WINED3DTS_PROJECTION,
4005 &proj_mat);
4006 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4007 WINED3DTS_WORLDMATRIX(0),
4008 &world_mat);
4010 TRACE("View mat:\n");
4011 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);
4012 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);
4013 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);
4014 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);
4016 TRACE("Proj mat:\n");
4017 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);
4018 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);
4019 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);
4020 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);
4022 TRACE("World mat:\n");
4023 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);
4024 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);
4025 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);
4026 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);
4028 /* Get the viewport */
4029 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4030 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4031 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4033 multiply_matrix(&mat,&view_mat,&world_mat);
4034 multiply_matrix(&mat,&proj_mat,&mat);
4036 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4038 for (i = 0; i < dwCount; i+= 1) {
4039 unsigned int tex_index;
4041 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4042 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4043 /* The position first */
4044 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4045 const float *p = (const float *)(element->data + i * element->stride);
4046 float x, y, z, rhw;
4047 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4049 /* Multiplication with world, view and projection matrix */
4050 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);
4051 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);
4052 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);
4053 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);
4055 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4057 /* WARNING: The following things are taken from d3d7 and were not yet checked
4058 * against d3d8 or d3d9!
4061 /* Clipping conditions: From msdn
4063 * A vertex is clipped if it does not match the following requirements
4064 * -rhw < x <= rhw
4065 * -rhw < y <= rhw
4066 * 0 < z <= rhw
4067 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4069 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4070 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4074 if( !doClip ||
4075 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4076 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4077 ( rhw > eps ) ) ) {
4079 /* "Normal" viewport transformation (not clipped)
4080 * 1) The values are divided by rhw
4081 * 2) The y axis is negative, so multiply it with -1
4082 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4083 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4084 * 4) Multiply x with Width/2 and add Width/2
4085 * 5) The same for the height
4086 * 6) Add the viewpoint X and Y to the 2D coordinates and
4087 * The minimum Z value to z
4088 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4090 * Well, basically it's simply a linear transformation into viewport
4091 * coordinates
4094 x /= rhw;
4095 y /= rhw;
4096 z /= rhw;
4098 y *= -1;
4100 x *= vp.Width / 2;
4101 y *= vp.Height / 2;
4102 z *= vp.MaxZ - vp.MinZ;
4104 x += vp.Width / 2 + vp.X;
4105 y += vp.Height / 2 + vp.Y;
4106 z += vp.MinZ;
4108 rhw = 1 / rhw;
4109 } else {
4110 /* That vertex got clipped
4111 * Contrary to OpenGL it is not dropped completely, it just
4112 * undergoes a different calculation.
4114 TRACE("Vertex got clipped\n");
4115 x += rhw;
4116 y += rhw;
4118 x /= 2;
4119 y /= 2;
4121 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4122 * outside of the main vertex buffer memory. That needs some more
4123 * investigation...
4127 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4130 ( (float *) dest_ptr)[0] = x;
4131 ( (float *) dest_ptr)[1] = y;
4132 ( (float *) dest_ptr)[2] = z;
4133 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4135 dest_ptr += 3 * sizeof(float);
4137 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4138 dest_ptr += sizeof(float);
4141 if(dest_conv) {
4142 float w = 1 / rhw;
4143 ( (float *) dest_conv)[0] = x * w;
4144 ( (float *) dest_conv)[1] = y * w;
4145 ( (float *) dest_conv)[2] = z * w;
4146 ( (float *) dest_conv)[3] = w;
4148 dest_conv += 3 * sizeof(float);
4150 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4151 dest_conv += sizeof(float);
4155 if (DestFVF & WINED3DFVF_PSIZE) {
4156 dest_ptr += sizeof(DWORD);
4157 if(dest_conv) dest_conv += sizeof(DWORD);
4159 if (DestFVF & WINED3DFVF_NORMAL) {
4160 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4161 const float *normal = (const float *)(element->data + i * element->stride);
4162 /* AFAIK this should go into the lighting information */
4163 FIXME("Didn't expect the destination to have a normal\n");
4164 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4165 if(dest_conv) {
4166 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4170 if (DestFVF & WINED3DFVF_DIFFUSE) {
4171 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4172 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4173 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4175 static BOOL warned = FALSE;
4177 if(!warned) {
4178 ERR("No diffuse color in source, but destination has one\n");
4179 warned = TRUE;
4182 *( (DWORD *) dest_ptr) = 0xffffffff;
4183 dest_ptr += sizeof(DWORD);
4185 if(dest_conv) {
4186 *( (DWORD *) dest_conv) = 0xffffffff;
4187 dest_conv += sizeof(DWORD);
4190 else {
4191 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4192 if(dest_conv) {
4193 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4194 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4195 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4196 dest_conv += sizeof(DWORD);
4201 if (DestFVF & WINED3DFVF_SPECULAR)
4203 /* What's the color value in the feedback buffer? */
4204 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4205 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4206 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4208 static BOOL warned = FALSE;
4210 if(!warned) {
4211 ERR("No specular color in source, but destination has one\n");
4212 warned = TRUE;
4215 *( (DWORD *) dest_ptr) = 0xFF000000;
4216 dest_ptr += sizeof(DWORD);
4218 if(dest_conv) {
4219 *( (DWORD *) dest_conv) = 0xFF000000;
4220 dest_conv += sizeof(DWORD);
4223 else {
4224 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4225 if(dest_conv) {
4226 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4227 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4228 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4229 dest_conv += sizeof(DWORD);
4234 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4235 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4236 const float *tex_coord = (const float *)(element->data + i * element->stride);
4237 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4239 ERR("No source texture, but destination requests one\n");
4240 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4241 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4243 else {
4244 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4245 if(dest_conv) {
4246 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4252 if (dest_conv)
4254 ENTER_GL();
4256 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4257 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4258 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4259 dwCount * get_flexible_vertex_size(DestFVF),
4260 dest_conv_addr));
4261 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4263 LEAVE_GL();
4265 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4268 return WINED3D_OK;
4270 #undef copy_and_next
4272 /* Do not call while under the GL lock. */
4273 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4274 UINT VertexCount, IWineD3DBuffer *pDestBuffer, struct wined3d_vertex_declaration *pVertexDecl, DWORD flags,
4275 DWORD DestFVF)
4277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4278 struct wined3d_stream_info stream_info;
4279 const struct wined3d_gl_info *gl_info;
4280 struct wined3d_context *context;
4281 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4282 HRESULT hr;
4284 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4286 if(pVertexDecl) {
4287 ERR("Output vertex declaration not implemented yet\n");
4290 /* Need any context to write to the vbo. */
4291 context = context_acquire(This, NULL);
4292 gl_info = context->gl_info;
4294 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4295 * control the streamIsUP flag, thus restore it afterwards.
4297 This->stateBlock->state.user_stream = FALSE;
4298 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4299 This->stateBlock->state.user_stream = streamWasUP;
4301 if(vbo || SrcStartIndex) {
4302 unsigned int i;
4303 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4304 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4306 * Also get the start index in, but only loop over all elements if there's something to add at all.
4308 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4310 struct wined3d_stream_info_element *e;
4312 if (!(stream_info.use_map & (1 << i))) continue;
4314 e = &stream_info.elements[i];
4315 if (e->buffer_object)
4317 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4318 e->buffer_object = 0;
4319 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4320 ENTER_GL();
4321 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4322 vb->buffer_object = 0;
4323 LEAVE_GL();
4325 if (e->data) e->data += e->stride * SrcStartIndex;
4329 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4330 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4332 context_release(context);
4334 return hr;
4337 /*****
4338 * Get / Set Texture Stage States
4339 * TODO: Verify against dx9 definitions
4340 *****/
4341 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4344 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4345 DWORD oldValue;
4347 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4349 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4351 WARN("Invalid Type %d passed.\n", Type);
4352 return WINED3D_OK;
4355 if (Stage >= gl_info->limits.texture_stages)
4357 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4358 Stage, gl_info->limits.texture_stages - 1);
4359 return WINED3D_OK;
4362 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4363 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4364 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4366 if (This->isRecordingState) {
4367 TRACE("Recording... not performing anything\n");
4368 return WINED3D_OK;
4371 /* Checked after the assignments to allow proper stateblock recording */
4372 if(oldValue == Value) {
4373 TRACE("App is setting the old value over, nothing to do\n");
4374 return WINED3D_OK;
4377 if (Stage > This->stateBlock->state.lowest_disabled_stage
4378 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4379 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4381 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4382 * Changes in other states are important on disabled stages too
4384 return WINED3D_OK;
4387 if(Type == WINED3DTSS_COLOROP) {
4388 unsigned int i;
4390 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4391 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4392 * they have to be disabled
4394 * The current stage is dirtified below.
4396 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4398 TRACE("Additionally dirtifying stage %u\n", i);
4399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4401 This->stateBlock->state.lowest_disabled_stage = Stage;
4402 TRACE("New lowest disabled: %u\n", Stage);
4403 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4404 /* Previously disabled stage enabled. Stages above it may need enabling
4405 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4406 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4408 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4411 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4413 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4414 break;
4415 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4418 This->stateBlock->state.lowest_disabled_stage = i;
4419 TRACE("New lowest disabled: %u\n", i);
4423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4425 return WINED3D_OK;
4428 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 TRACE("iface %p, stage %u, state %s, value %p.\n",
4433 iface, Stage, debug_d3dtexturestate(Type), pValue);
4435 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4437 WARN("Invalid Type %d passed.\n", Type);
4438 return WINED3D_OK;
4441 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4442 TRACE("Returning %#x.\n", *pValue);
4444 return WINED3D_OK;
4447 /*****
4448 * Get / Set Texture
4449 *****/
4450 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4451 DWORD stage, IWineD3DBaseTexture *texture)
4453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4454 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4455 IWineD3DBaseTexture *prev;
4457 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4459 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4460 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4462 /* Windows accepts overflowing this array... we do not. */
4463 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4465 WARN("Ignoring invalid stage %u.\n", stage);
4466 return WINED3D_OK;
4469 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4470 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4472 WARN("Rejecting attempt to set scratch texture.\n");
4473 return WINED3DERR_INVALIDCALL;
4476 This->updateStateBlock->changed.textures |= 1 << stage;
4478 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4479 TRACE("Previous texture %p.\n", prev);
4481 if (texture == prev)
4483 TRACE("App is setting the same texture again, nothing to do.\n");
4484 return WINED3D_OK;
4487 TRACE("Setting new texture to %p.\n", texture);
4488 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4490 if (This->isRecordingState)
4492 TRACE("Recording... not performing anything\n");
4494 if (texture) IWineD3DBaseTexture_AddRef(texture);
4495 if (prev) IWineD3DBaseTexture_Release(prev);
4497 return WINED3D_OK;
4500 if (texture)
4502 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4503 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4504 GLenum dimensions = t->baseTexture.target;
4506 IWineD3DBaseTexture_AddRef(texture);
4508 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4511 if (!prev && stage < gl_info->limits.texture_stages)
4513 /* The source arguments for color and alpha ops have different
4514 * meanings when a NULL texture is bound, so the COLOROP and
4515 * ALPHAOP have to be dirtified. */
4516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4520 if (bind_count == 1) t->baseTexture.sampler = stage;
4523 if (prev)
4525 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4526 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4528 IWineD3DBaseTexture_Release(prev);
4530 if (!texture && stage < gl_info->limits.texture_stages)
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4536 if (bind_count && t->baseTexture.sampler == stage)
4538 unsigned int i;
4540 /* Search for other stages the texture is bound to. Shouldn't
4541 * happen if applications bind textures to a single stage only. */
4542 TRACE("Searching for other stages the texture is bound to.\n");
4543 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4545 if (This->updateStateBlock->state.textures[i] == t)
4547 TRACE("Texture is also bound to stage %u.\n", i);
4548 t->baseTexture.sampler = i;
4549 break;
4555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4557 return WINED3D_OK;
4560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4563 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4565 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4566 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4569 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4571 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4572 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4575 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4576 if (*ppTexture)
4577 IWineD3DBaseTexture_AddRef(*ppTexture);
4579 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4581 return WINED3D_OK;
4584 /*****
4585 * Get Back Buffer
4586 *****/
4587 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4588 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4590 IWineD3DSwapChain *swapchain;
4591 HRESULT hr;
4593 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4594 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4596 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4597 if (FAILED(hr))
4599 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4600 return hr;
4603 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4604 IWineD3DSwapChain_Release(swapchain);
4605 if (FAILED(hr))
4607 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4608 return hr;
4611 return WINED3D_OK;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS *caps)
4616 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4618 TRACE("iface %p, caps %p.\n", iface, caps);
4620 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal, device->devType, caps);
4623 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 IWineD3DSwapChain *swapChain;
4626 HRESULT hr;
4628 if(iSwapChain > 0) {
4629 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4630 if (hr == WINED3D_OK) {
4631 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4632 IWineD3DSwapChain_Release(swapChain);
4633 } else {
4634 FIXME("(%p) Error getting display mode\n", This);
4636 } else {
4637 /* Don't read the real display mode,
4638 but return the stored mode instead. X11 can't change the color
4639 depth, and some apps are pretty angry if they SetDisplayMode from
4640 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4642 Also don't relay to the swapchain because with ddraw it's possible
4643 that there isn't a swapchain at all */
4644 pMode->Width = This->ddraw_width;
4645 pMode->Height = This->ddraw_height;
4646 pMode->Format = This->ddraw_format;
4647 pMode->RefreshRate = 0;
4648 hr = WINED3D_OK;
4651 return hr;
4654 /*****
4655 * Stateblock related functions
4656 *****/
4658 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 struct wined3d_stateblock *stateblock;
4662 HRESULT hr;
4664 TRACE("(%p)\n", This);
4666 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4668 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4669 if (FAILED(hr)) return hr;
4671 wined3d_stateblock_decref(This->updateStateBlock);
4672 This->updateStateBlock = stateblock;
4673 This->isRecordingState = TRUE;
4675 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4677 return WINED3D_OK;
4680 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface,
4681 struct wined3d_stateblock **stateblock)
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4684 struct wined3d_stateblock *object = This->updateStateBlock;
4686 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
4688 if (!This->isRecordingState) {
4689 WARN("(%p) not recording! returning error\n", This);
4690 *stateblock = NULL;
4691 return WINED3DERR_INVALIDCALL;
4694 stateblock_init_contained_states(object);
4696 *stateblock = object;
4697 This->isRecordingState = FALSE;
4698 This->updateStateBlock = This->stateBlock;
4699 wined3d_stateblock_incref(This->updateStateBlock);
4701 TRACE("Returning stateblock %p.\n", *stateblock);
4703 return WINED3D_OK;
4706 /*****
4707 * Scene related functions
4708 *****/
4709 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4710 /* At the moment we have no need for any functionality at the beginning
4711 of a scene */
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p)\n", This);
4715 if(This->inScene) {
4716 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4717 return WINED3DERR_INVALIDCALL;
4719 This->inScene = TRUE;
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 struct wined3d_context *context;
4728 TRACE("(%p)\n", This);
4730 if(!This->inScene) {
4731 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4732 return WINED3DERR_INVALIDCALL;
4735 context = context_acquire(This, NULL);
4736 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4737 wglFlush();
4738 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4739 * fails. */
4740 context_release(context);
4742 This->inScene = FALSE;
4743 return WINED3D_OK;
4746 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4747 const RECT *pSourceRect, const RECT *pDestRect,
4748 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4750 IWineD3DSwapChain *swapChain = NULL;
4751 int i;
4752 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4754 TRACE("iface %p.\n", iface);
4756 for(i = 0 ; i < swapchains ; i ++) {
4758 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4759 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4760 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4761 IWineD3DSwapChain_Release(swapChain);
4764 return WINED3D_OK;
4767 /* Do not call while under the GL lock. */
4768 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4769 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4771 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4772 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4773 RECT draw_rect;
4775 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4776 iface, rect_count, rects, flags, color, depth, stencil);
4778 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4780 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4781 /* TODO: What about depth stencil buffers without stencil bits? */
4782 return WINED3DERR_INVALIDCALL;
4785 device_get_draw_rect(device, &draw_rect);
4787 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4788 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4791 /*****
4792 * Drawing functions
4793 *****/
4795 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4796 WINED3DPRIMITIVETYPE primitive_type)
4798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4802 This->updateStateBlock->changed.primitive_type = TRUE;
4803 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4806 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4807 WINED3DPRIMITIVETYPE *primitive_type)
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4813 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4815 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4818 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4822 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4824 if (!This->stateBlock->state.vertex_declaration)
4826 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4827 return WINED3DERR_INVALIDCALL;
4830 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4831 if (This->stateBlock->state.user_stream)
4833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4834 This->stateBlock->state.user_stream = FALSE;
4837 if (This->stateBlock->state.load_base_vertex_index)
4839 This->stateBlock->state.load_base_vertex_index = 0;
4840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4842 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4843 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4850 struct wined3d_buffer *index_buffer;
4851 UINT idxStride = 2;
4852 GLuint vbo;
4854 index_buffer = This->stateBlock->state.index_buffer;
4855 if (!index_buffer)
4857 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4858 * without an index buffer set. (The first time at least...)
4859 * D3D8 simply dies, but I doubt it can do much harm to return
4860 * D3DERR_INVALIDCALL there as well. */
4861 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4862 return WINED3DERR_INVALIDCALL;
4865 if (!This->stateBlock->state.vertex_declaration)
4867 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4868 return WINED3DERR_INVALIDCALL;
4871 if (This->stateBlock->state.user_stream)
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4874 This->stateBlock->state.user_stream = FALSE;
4876 vbo = index_buffer->buffer_object;
4878 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4880 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4881 idxStride = 2;
4882 else
4883 idxStride = 4;
4885 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4887 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4891 drawPrimitive(This, index_count, startIndex, idxStride,
4892 vbo ? NULL : index_buffer->resource.allocatedMemory);
4894 return WINED3D_OK;
4897 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4898 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 struct wined3d_stream_state *stream;
4902 IWineD3DBuffer *vb;
4904 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4905 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4907 if (!This->stateBlock->state.vertex_declaration)
4909 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4910 return WINED3DERR_INVALIDCALL;
4913 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4914 stream = &This->stateBlock->state.streams[0];
4915 vb = (IWineD3DBuffer *)stream->buffer;
4916 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4917 if (vb) IWineD3DBuffer_Release(vb);
4918 stream->offset = 0;
4919 stream->stride = VertexStreamZeroStride;
4920 This->stateBlock->state.user_stream = TRUE;
4921 This->stateBlock->state.load_base_vertex_index = 0;
4923 /* TODO: Only mark dirty if drawing from a different UP address */
4924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4926 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4928 /* MSDN specifies stream zero settings must be set to NULL */
4929 stream->buffer = NULL;
4930 stream->stride = 0;
4932 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4933 * the new stream sources or use UP drawing again
4935 return WINED3D_OK;
4938 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4939 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4940 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4942 int idxStride;
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4944 struct wined3d_stream_state *stream;
4945 IWineD3DBuffer *vb;
4946 IWineD3DBuffer *ib;
4948 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4949 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4951 if (!This->stateBlock->state.vertex_declaration)
4953 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4954 return WINED3DERR_INVALIDCALL;
4957 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4958 idxStride = 2;
4959 } else {
4960 idxStride = 4;
4963 stream = &This->stateBlock->state.streams[0];
4964 vb = (IWineD3DBuffer *)stream->buffer;
4965 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4966 if (vb) IWineD3DBuffer_Release(vb);
4967 stream->offset = 0;
4968 stream->stride = VertexStreamZeroStride;
4969 This->stateBlock->state.user_stream = TRUE;
4971 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4972 This->stateBlock->state.base_vertex_index = 0;
4973 This->stateBlock->state.load_base_vertex_index = 0;
4974 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4978 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4980 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4981 stream->buffer = NULL;
4982 stream->stride = 0;
4983 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4984 if (ib)
4986 IWineD3DBuffer_Release(ib);
4987 This->stateBlock->state.index_buffer = NULL;
4989 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4990 * SetStreamSource to specify a vertex buffer
4993 return WINED3D_OK;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4997 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5001 /* Mark the state dirty until we have nicer tracking
5002 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5003 * that value.
5005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5007 This->stateBlock->state.base_vertex_index = 0;
5008 This->up_strided = DrawPrimStrideData;
5009 drawPrimitive(This, vertex_count, 0, 0, NULL);
5010 This->up_strided = NULL;
5011 return WINED3D_OK;
5014 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5015 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5016 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5019 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5021 /* Mark the state dirty until we have nicer tracking
5022 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5023 * that value.
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5027 This->stateBlock->state.user_stream = TRUE;
5028 This->stateBlock->state.base_vertex_index = 0;
5029 This->up_strided = DrawPrimStrideData;
5030 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
5031 This->up_strided = NULL;
5032 return WINED3D_OK;
5035 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5036 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
5037 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
5039 WINED3DLOCKED_BOX src;
5040 WINED3DLOCKED_BOX dst;
5041 HRESULT hr;
5043 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5044 iface, pSourceVolume, pDestinationVolume);
5046 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5047 * dirtification to improve loading performance.
5049 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5050 if (FAILED(hr)) return hr;
5051 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5052 if (FAILED(hr))
5054 IWineD3DVolume_Unmap(pSourceVolume);
5055 return hr;
5058 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5060 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5061 if (FAILED(hr))
5062 IWineD3DVolume_Unmap(pSourceVolume);
5063 else
5064 hr = IWineD3DVolume_Unmap(pSourceVolume);
5066 return hr;
5069 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5070 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5072 unsigned int level_count, i;
5073 WINED3DRESOURCETYPE type;
5074 HRESULT hr;
5076 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5078 /* Verify that the source and destination textures are non-NULL. */
5079 if (!src_texture || !dst_texture)
5081 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5082 return WINED3DERR_INVALIDCALL;
5085 if (src_texture == dst_texture)
5087 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5088 return WINED3DERR_INVALIDCALL;
5091 /* Verify that the source and destination textures are the same type. */
5092 type = IWineD3DBaseTexture_GetType(src_texture);
5093 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5095 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5096 return WINED3DERR_INVALIDCALL;
5099 /* Check that both textures have the identical numbers of levels. */
5100 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5101 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5103 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5104 return WINED3DERR_INVALIDCALL;
5107 /* Make sure that the destination texture is loaded. */
5108 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5109 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5111 /* Update every surface level of the texture. */
5112 switch (type)
5114 case WINED3DRTYPE_TEXTURE:
5116 IWineD3DSurface *src_surface;
5117 IWineD3DSurface *dst_surface;
5119 for (i = 0; i < level_count; ++i)
5121 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5122 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5123 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5124 IWineD3DSurface_Release(dst_surface);
5125 IWineD3DSurface_Release(src_surface);
5126 if (FAILED(hr))
5128 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5129 return hr;
5132 break;
5135 case WINED3DRTYPE_CUBETEXTURE:
5137 IWineD3DSurface *src_surface;
5138 IWineD3DSurface *dst_surface;
5140 for (i = 0; i < level_count * 6; ++i)
5142 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5143 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5144 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5145 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5146 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5147 IWineD3DSurface_Release(dst_surface);
5148 IWineD3DSurface_Release(src_surface);
5149 if (FAILED(hr))
5151 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5152 return hr;
5155 break;
5158 case WINED3DRTYPE_VOLUMETEXTURE:
5160 IWineD3DVolume *src_volume;
5161 IWineD3DVolume *dst_volume;
5163 for (i = 0; i < level_count; ++i)
5165 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5166 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5167 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5168 IWineD3DVolume_Release(dst_volume);
5169 IWineD3DVolume_Release(src_volume);
5170 if (FAILED(hr))
5172 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5173 return hr;
5176 break;
5179 default:
5180 FIXME("Unsupported texture type %#x.\n", type);
5181 return WINED3DERR_INVALIDCALL;
5184 return WINED3D_OK;
5187 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5188 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5190 IWineD3DSwapChain *swapchain;
5191 HRESULT hr;
5193 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5195 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5196 if (FAILED(hr)) return hr;
5198 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5199 IWineD3DSwapChain_Release(swapchain);
5201 return hr;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 IWineD3DBaseTextureImpl *texture;
5207 DWORD i;
5209 TRACE("(%p) : %p\n", This, pNumPasses);
5211 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5213 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5215 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5216 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5218 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5220 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5221 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5224 texture = This->stateBlock->state.textures[i];
5225 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5227 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5229 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5230 return E_FAIL;
5232 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5234 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5235 return E_FAIL;
5237 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5238 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5240 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5241 return E_FAIL;
5245 /* return a sensible default */
5246 *pNumPasses = 1;
5248 TRACE("returning D3D_OK\n");
5249 return WINED3D_OK;
5252 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5254 int i;
5256 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5258 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5259 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5260 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5262 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5267 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5269 int j;
5270 UINT NewSize;
5271 PALETTEENTRY **palettes;
5273 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5275 if (PaletteNumber >= MAX_PALETTES) {
5276 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5277 return WINED3DERR_INVALIDCALL;
5280 if (PaletteNumber >= This->NumberOfPalettes) {
5281 NewSize = This->NumberOfPalettes;
5282 do {
5283 NewSize *= 2;
5284 } while(PaletteNumber >= NewSize);
5285 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5286 if (!palettes) {
5287 ERR("Out of memory!\n");
5288 return E_OUTOFMEMORY;
5290 This->palettes = palettes;
5291 This->NumberOfPalettes = NewSize;
5294 if (!This->palettes[PaletteNumber]) {
5295 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5296 if (!This->palettes[PaletteNumber]) {
5297 ERR("Out of memory!\n");
5298 return E_OUTOFMEMORY;
5302 for (j = 0; j < 256; ++j) {
5303 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5304 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5305 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5306 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5308 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5309 TRACE("(%p) : returning\n", This);
5310 return WINED3D_OK;
5313 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 int j;
5316 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5317 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5318 /* What happens in such situation isn't documented; Native seems to silently abort
5319 on such conditions. Return Invalid Call. */
5320 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5321 return WINED3DERR_INVALIDCALL;
5323 for (j = 0; j < 256; ++j) {
5324 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5325 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5326 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5327 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5329 TRACE("(%p) : returning\n", This);
5330 return WINED3D_OK;
5333 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5336 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5337 (tested with reference rasterizer). Return Invalid Call. */
5338 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5339 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5340 return WINED3DERR_INVALIDCALL;
5342 /*TODO: stateblocks */
5343 if (This->currentPalette != PaletteNumber) {
5344 This->currentPalette = PaletteNumber;
5345 dirtify_p8_texture_samplers(This);
5347 TRACE("(%p) : returning\n", This);
5348 return WINED3D_OK;
5351 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5354 if (!PaletteNumber)
5356 WARN("(%p) : returning Invalid Call\n", This);
5357 return WINED3DERR_INVALIDCALL;
5359 /*TODO: stateblocks */
5360 *PaletteNumber = This->currentPalette;
5361 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5362 return WINED3D_OK;
5365 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 static BOOL warned;
5368 if (!warned)
5370 FIXME("(%p) : stub\n", This);
5371 warned = TRUE;
5374 This->softwareVertexProcessing = bSoftware;
5375 return WINED3D_OK;
5379 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 static BOOL warned;
5382 if (!warned)
5384 FIXME("(%p) : stub\n", This);
5385 warned = TRUE;
5387 return This->softwareVertexProcessing;
5390 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5391 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5393 IWineD3DSwapChain *swapchain;
5394 HRESULT hr;
5396 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5397 iface, swapchain_idx, raster_status);
5399 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5400 if (FAILED(hr))
5402 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5403 return hr;
5406 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5407 IWineD3DSwapChain_Release(swapchain);
5408 if (FAILED(hr))
5410 WARN("Failed to get raster status, hr %#x.\n", hr);
5411 return hr;
5414 return WINED3D_OK;
5417 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5419 static BOOL warned;
5420 if(nSegments != 0.0f) {
5421 if (!warned)
5423 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5424 warned = TRUE;
5427 return WINED3D_OK;
5430 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5432 static BOOL warned;
5433 if (!warned)
5435 FIXME("iface %p stub!\n", iface);
5436 warned = TRUE;
5438 return 0.0f;
5441 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5442 IWineD3DSurface *src_surface, const RECT *src_rect,
5443 IWineD3DSurface *dst_surface, const POINT *dst_point)
5445 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5446 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5448 const struct wined3d_format *src_format;
5449 const struct wined3d_format *dst_format;
5450 const struct wined3d_gl_info *gl_info;
5451 struct wined3d_context *context;
5452 const unsigned char *data;
5453 UINT update_w, update_h;
5454 CONVERT_TYPES convert;
5455 UINT src_w, src_h;
5456 UINT dst_x, dst_y;
5457 DWORD sampler;
5458 struct wined3d_format format;
5460 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5461 iface, src_surface, wine_dbgstr_rect(src_rect),
5462 dst_surface, wine_dbgstr_point(dst_point));
5464 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5466 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5467 src_surface, dst_surface);
5468 return WINED3DERR_INVALIDCALL;
5471 src_format = src_impl->resource.format;
5472 dst_format = dst_impl->resource.format;
5474 if (src_format->id != dst_format->id)
5476 WARN("Source and destination surfaces should have the same format.\n");
5477 return WINED3DERR_INVALIDCALL;
5480 dst_x = dst_point ? dst_point->x : 0;
5481 dst_y = dst_point ? dst_point->y : 0;
5483 /* This call loads the OpenGL surface directly, instead of copying the
5484 * surface to the destination's sysmem copy. If surface conversion is
5485 * needed, use BltFast instead to copy in sysmem and use regular surface
5486 * loading. */
5487 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5488 if (convert != NO_CONVERSION || format.convert)
5489 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5491 context = context_acquire(This, NULL);
5492 gl_info = context->gl_info;
5494 ENTER_GL();
5495 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5496 checkGLcall("glActiveTextureARB");
5497 LEAVE_GL();
5499 /* Make sure the surface is loaded and up to date */
5500 surface_internal_preload(dst_impl, SRGB_RGB);
5501 surface_bind(dst_impl, FALSE);
5503 src_w = src_impl->currentDesc.Width;
5504 src_h = src_impl->currentDesc.Height;
5505 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5506 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5508 data = src_impl->resource.allocatedMemory;
5509 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5511 ENTER_GL();
5513 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5515 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5516 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5517 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5519 if (src_rect)
5521 data += (src_rect->top / src_format->block_height) * src_pitch;
5522 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5525 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5526 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5527 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5529 if (row_length == src_pitch)
5531 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5532 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5534 else
5536 UINT row, y;
5538 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5539 * can't use the unpack row length like below. */
5540 for (row = 0, y = dst_y; row < row_count; ++row)
5542 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5543 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5544 y += src_format->block_height;
5545 data += src_pitch;
5548 checkGLcall("glCompressedTexSubImage2DARB");
5550 else
5552 if (src_rect)
5554 data += src_rect->top * src_w * src_format->byte_count;
5555 data += src_rect->left * src_format->byte_count;
5558 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5559 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5560 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5562 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5563 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5564 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5565 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5566 checkGLcall("glTexSubImage2D");
5569 LEAVE_GL();
5570 context_release(context);
5572 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5573 sampler = This->rev_tex_unit_map[0];
5574 if (sampler != WINED3D_UNMAPPED_STAGE)
5576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5579 return WINED3D_OK;
5582 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5584 struct WineD3DRectPatch *patch;
5585 GLenum old_primitive_type;
5586 unsigned int i;
5587 struct list *e;
5588 BOOL found;
5589 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5591 if(!(Handle || pRectPatchInfo)) {
5592 /* TODO: Write a test for the return value, thus the FIXME */
5593 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5594 return WINED3DERR_INVALIDCALL;
5597 if(Handle) {
5598 i = PATCHMAP_HASHFUNC(Handle);
5599 found = FALSE;
5600 LIST_FOR_EACH(e, &This->patches[i]) {
5601 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5602 if(patch->Handle == Handle) {
5603 found = TRUE;
5604 break;
5608 if(!found) {
5609 TRACE("Patch does not exist. Creating a new one\n");
5610 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5611 patch->Handle = Handle;
5612 list_add_head(&This->patches[i], &patch->entry);
5613 } else {
5614 TRACE("Found existing patch %p\n", patch);
5616 } else {
5617 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5618 * attributes we have to tesselate, read back, and draw. This needs a patch
5619 * management structure instance. Create one.
5621 * A possible improvement is to check if a vertex shader is used, and if not directly
5622 * draw the patch.
5624 FIXME("Drawing an uncached patch. This is slow\n");
5625 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5628 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5629 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5630 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5632 HRESULT hr;
5633 TRACE("Tesselation density or patch info changed, retesselating\n");
5635 if(pRectPatchInfo) {
5636 patch->RectPatchInfo = *pRectPatchInfo;
5638 patch->numSegs[0] = pNumSegs[0];
5639 patch->numSegs[1] = pNumSegs[1];
5640 patch->numSegs[2] = pNumSegs[2];
5641 patch->numSegs[3] = pNumSegs[3];
5643 hr = tesselate_rectpatch(This, patch);
5644 if(FAILED(hr)) {
5645 WARN("Patch tesselation failed\n");
5647 /* Do not release the handle to store the params of the patch */
5648 if(!Handle) {
5649 HeapFree(GetProcessHeap(), 0, patch);
5651 return hr;
5655 This->currentPatch = patch;
5656 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5657 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5658 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5659 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5660 This->currentPatch = NULL;
5662 /* Destroy uncached patches */
5663 if(!Handle) {
5664 HeapFree(GetProcessHeap(), 0, patch->mem);
5665 HeapFree(GetProcessHeap(), 0, patch);
5667 return WINED3D_OK;
5670 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5671 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5673 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5674 iface, handle, segment_count, patch_info);
5676 return WINED3D_OK;
5679 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 int i;
5682 struct WineD3DRectPatch *patch;
5683 struct list *e;
5684 TRACE("(%p) Handle(%d)\n", This, Handle);
5686 i = PATCHMAP_HASHFUNC(Handle);
5687 LIST_FOR_EACH(e, &This->patches[i]) {
5688 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5689 if(patch->Handle == Handle) {
5690 TRACE("Deleting patch %p\n", patch);
5691 list_remove(&patch->entry);
5692 HeapFree(GetProcessHeap(), 0, patch->mem);
5693 HeapFree(GetProcessHeap(), 0, patch);
5694 return WINED3D_OK;
5698 /* TODO: Write a test for the return value */
5699 FIXME("Attempt to destroy nonexistent patch\n");
5700 return WINED3DERR_INVALIDCALL;
5703 /* Do not call while under the GL lock. */
5704 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5705 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5707 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5709 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5710 iface, surface, wine_dbgstr_rect(rect),
5711 color->r, color->g, color->b, color->a);
5713 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5715 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5716 return WINED3DERR_INVALIDCALL;
5719 return surface_color_fill(s, rect, color);
5722 /* Do not call while under the GL lock. */
5723 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5724 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5726 IWineD3DResource *resource;
5727 HRESULT hr;
5729 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5730 if (FAILED(hr))
5732 ERR("Failed to get resource, hr %#x\n", hr);
5733 return;
5736 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5738 FIXME("Only supported on surface resources\n");
5739 IWineD3DResource_Release(resource);
5740 return;
5743 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5744 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5746 IWineD3DResource_Release(resource);
5749 /* rendertarget and depth stencil functions */
5750 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5751 DWORD render_target_idx, IWineD3DSurface **render_target)
5753 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5755 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5756 iface, render_target_idx, render_target);
5758 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5760 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5761 return WINED3DERR_INVALIDCALL;
5764 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5765 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5767 TRACE("Returning render target %p.\n", *render_target);
5769 return WINED3D_OK;
5772 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5774 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5776 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5778 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5779 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5780 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5781 IWineD3DSurface_AddRef(*depth_stencil);
5783 return WINED3D_OK;
5786 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5787 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5789 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5790 IWineD3DSurfaceImpl *prev;
5792 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5793 iface, render_target_idx, render_target, set_viewport);
5795 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5797 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5798 return WINED3DERR_INVALIDCALL;
5801 prev = device->render_targets[render_target_idx];
5802 if (render_target == (IWineD3DSurface *)prev)
5804 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5805 return WINED3D_OK;
5808 /* Render target 0 can't be set to NULL. */
5809 if (!render_target && !render_target_idx)
5811 WARN("Trying to set render target 0 to NULL.\n");
5812 return WINED3DERR_INVALIDCALL;
5815 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5817 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5818 return WINED3DERR_INVALIDCALL;
5821 if (render_target) IWineD3DSurface_AddRef(render_target);
5822 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5823 /* Release after the assignment, to prevent device_resource_released()
5824 * from seeing the surface as still in use. */
5825 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5827 /* Render target 0 is special. */
5828 if (!render_target_idx && set_viewport)
5830 /* Set the viewport and scissor rectangles, if requested. Tests show
5831 * that stateblock recording is ignored, the change goes directly
5832 * into the primary stateblock. */
5833 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5834 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5835 device->stateBlock->state.viewport.X = 0;
5836 device->stateBlock->state.viewport.Y = 0;
5837 device->stateBlock->state.viewport.MaxZ = 1.0f;
5838 device->stateBlock->state.viewport.MinZ = 0.0f;
5839 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5841 device->stateBlock->state.scissor_rect.top = 0;
5842 device->stateBlock->state.scissor_rect.left = 0;
5843 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5844 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5845 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5848 return WINED3D_OK;
5851 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 IWineD3DSurfaceImpl *tmp;
5856 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5858 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5860 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5861 return WINED3D_OK;
5864 if (This->depth_stencil)
5866 if (This->swapchains[0]->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5867 || This->depth_stencil->flags & SFLAG_DISCARD)
5869 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5870 This->depth_stencil->currentDesc.Width,
5871 This->depth_stencil->currentDesc.Height);
5872 if (This->depth_stencil == This->onscreen_depth_stencil)
5874 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5875 This->onscreen_depth_stencil = NULL;
5880 tmp = This->depth_stencil;
5881 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5882 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5883 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5885 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5887 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5893 return WINED3D_OK;
5896 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5897 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5900 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5901 WINED3DLOCKED_RECT lockedRect;
5903 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5904 iface, XHotSpot, YHotSpot, cursor_image);
5906 /* some basic validation checks */
5907 if (This->cursorTexture)
5909 struct wined3d_context *context = context_acquire(This, NULL);
5910 ENTER_GL();
5911 glDeleteTextures(1, &This->cursorTexture);
5912 LEAVE_GL();
5913 context_release(context);
5914 This->cursorTexture = 0;
5917 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5918 This->haveHardwareCursor = TRUE;
5919 else
5920 This->haveHardwareCursor = FALSE;
5922 if (cursor_image)
5924 WINED3DLOCKED_RECT rect;
5926 /* MSDN: Cursor must be A8R8G8B8 */
5927 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5929 WARN("surface %p has an invalid format.\n", cursor_image);
5930 return WINED3DERR_INVALIDCALL;
5933 /* MSDN: Cursor must be smaller than the display mode */
5934 if (s->currentDesc.Width > This->ddraw_width
5935 || s->currentDesc.Height > This->ddraw_height)
5937 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5938 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5939 return WINED3DERR_INVALIDCALL;
5942 if (!This->haveHardwareCursor) {
5943 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5945 /* Do not store the surface's pointer because the application may
5946 * release it after setting the cursor image. Windows doesn't
5947 * addref the set surface, so we can't do this either without
5948 * creating circular refcount dependencies. Copy out the gl texture
5949 * instead.
5951 This->cursorWidth = s->currentDesc.Width;
5952 This->cursorHeight = s->currentDesc.Height;
5953 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5955 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5956 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5957 struct wined3d_context *context;
5958 char *mem, *bits = rect.pBits;
5959 GLint intfmt = format->glInternal;
5960 GLint gl_format = format->glFormat;
5961 GLint type = format->glType;
5962 INT height = This->cursorHeight;
5963 INT width = This->cursorWidth;
5964 INT bpp = format->byte_count;
5965 DWORD sampler;
5966 INT i;
5968 /* Reformat the texture memory (pitch and width can be
5969 * different) */
5970 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5971 for(i = 0; i < height; i++)
5972 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5973 IWineD3DSurface_Unmap(cursor_image);
5975 context = context_acquire(This, NULL);
5977 ENTER_GL();
5979 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5981 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5982 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5985 /* Make sure that a proper texture unit is selected */
5986 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5987 checkGLcall("glActiveTextureARB");
5988 sampler = This->rev_tex_unit_map[0];
5989 if (sampler != WINED3D_UNMAPPED_STAGE)
5991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5993 /* Create a new cursor texture */
5994 glGenTextures(1, &This->cursorTexture);
5995 checkGLcall("glGenTextures");
5996 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5997 checkGLcall("glBindTexture");
5998 /* Copy the bitmap memory into the cursor texture */
5999 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
6000 checkGLcall("glTexImage2D");
6001 HeapFree(GetProcessHeap(), 0, mem);
6003 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6005 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6006 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6009 LEAVE_GL();
6011 context_release(context);
6013 else
6015 FIXME("A cursor texture was not returned.\n");
6016 This->cursorTexture = 0;
6019 else
6021 /* Draw a hardware cursor */
6022 ICONINFO cursorInfo;
6023 HCURSOR cursor;
6024 /* Create and clear maskBits because it is not needed for
6025 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6026 * chunks. */
6027 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6028 (s->currentDesc.Width * s->currentDesc.Height / 8));
6029 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
6030 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
6031 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
6033 cursorInfo.fIcon = FALSE;
6034 cursorInfo.xHotspot = XHotSpot;
6035 cursorInfo.yHotspot = YHotSpot;
6036 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
6037 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
6038 IWineD3DSurface_Unmap(cursor_image);
6039 /* Create our cursor and clean up. */
6040 cursor = CreateIconIndirect(&cursorInfo);
6041 SetCursor(cursor);
6042 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6043 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6044 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6045 This->hardwareCursor = cursor;
6046 HeapFree(GetProcessHeap(), 0, maskBits);
6050 This->xHotSpot = XHotSpot;
6051 This->yHotSpot = YHotSpot;
6052 return WINED3D_OK;
6055 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6056 int XScreenSpace, int YScreenSpace, DWORD flags)
6058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6060 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6061 iface, XScreenSpace, YScreenSpace, flags);
6063 This->xScreenSpace = XScreenSpace;
6064 This->yScreenSpace = YScreenSpace;
6067 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6069 BOOL oldVisible = This->bCursorVisible;
6070 POINT pt;
6072 TRACE("(%p) : visible(%d)\n", This, bShow);
6075 * When ShowCursor is first called it should make the cursor appear at the OS's last
6076 * known cursor position. Because of this, some applications just repetitively call
6077 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6079 GetCursorPos(&pt);
6080 This->xScreenSpace = pt.x;
6081 This->yScreenSpace = pt.y;
6083 if (This->haveHardwareCursor) {
6084 This->bCursorVisible = bShow;
6085 if (bShow)
6086 SetCursor(This->hardwareCursor);
6087 else
6088 SetCursor(NULL);
6090 else
6092 if (This->cursorTexture)
6093 This->bCursorVisible = bShow;
6096 return oldVisible;
6099 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6100 TRACE("checking resource %p for eviction\n", resource);
6101 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6102 TRACE("Evicting %p\n", resource);
6103 IWineD3DResource_UnLoad(resource);
6105 IWineD3DResource_Release(resource);
6106 return S_OK;
6109 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6111 TRACE("iface %p.\n", iface);
6113 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6114 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6115 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6117 return WINED3D_OK;
6120 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6122 IWineD3DDeviceImpl *device = surface->resource.device;
6123 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6125 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6126 if (surface->flags & SFLAG_DIBSECTION)
6128 /* Release the DC */
6129 SelectObject(surface->hDC, surface->dib.holdbitmap);
6130 DeleteDC(surface->hDC);
6131 /* Release the DIB section */
6132 DeleteObject(surface->dib.DIBsection);
6133 surface->dib.bitmap_data = NULL;
6134 surface->resource.allocatedMemory = NULL;
6135 surface->flags &= ~SFLAG_DIBSECTION;
6137 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6138 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6139 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6140 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6142 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6143 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6144 } else {
6145 surface->pow2Width = surface->pow2Height = 1;
6146 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6147 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6150 if (surface->texture_name)
6152 struct wined3d_context *context = context_acquire(device, NULL);
6153 ENTER_GL();
6154 glDeleteTextures(1, &surface->texture_name);
6155 LEAVE_GL();
6156 context_release(context);
6157 surface->texture_name = 0;
6158 surface->flags &= ~SFLAG_CLIENT;
6160 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6161 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6163 surface->flags |= SFLAG_NONPOW2;
6165 else
6167 surface->flags &= ~SFLAG_NONPOW2;
6169 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6170 surface->resource.allocatedMemory = NULL;
6171 surface->resource.heapMemory = NULL;
6172 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6174 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6175 * to a FBO */
6176 if (!surface_init_sysmem(surface))
6178 return E_OUTOFMEMORY;
6180 return WINED3D_OK;
6183 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6184 TRACE("Unloading resource %p\n", resource);
6185 IWineD3DResource_UnLoad(resource);
6186 IWineD3DResource_Release(resource);
6187 return S_OK;
6190 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6192 UINT i, count;
6193 WINED3DDISPLAYMODE m;
6194 HRESULT hr;
6196 /* All Windowed modes are supported, as is leaving the current mode */
6197 if(pp->Windowed) return TRUE;
6198 if(!pp->BackBufferWidth) return TRUE;
6199 if(!pp->BackBufferHeight) return TRUE;
6201 count = wined3d_get_adapter_mode_count(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6202 for (i = 0; i < count; ++i)
6204 memset(&m, 0, sizeof(m));
6205 hr = wined3d_enum_adapter_modes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6206 if (FAILED(hr))
6207 ERR("Failed to enumerate adapter mode.\n");
6208 if (m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight)
6209 /* Mode found, it is supported. */
6210 return TRUE;
6212 /* Mode not found -> not supported */
6213 return FALSE;
6216 /* Do not call while under the GL lock. */
6217 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6219 const struct wined3d_gl_info *gl_info;
6220 struct wined3d_context *context;
6221 IWineD3DBaseShaderImpl *shader;
6223 context = context_acquire(device, NULL);
6224 gl_info = context->gl_info;
6226 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, reset_unload_resources, NULL);
6227 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6229 device->shader_backend->shader_destroy(shader);
6232 ENTER_GL();
6233 if (device->depth_blt_texture)
6235 glDeleteTextures(1, &device->depth_blt_texture);
6236 device->depth_blt_texture = 0;
6238 if (device->depth_blt_rb)
6240 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6241 device->depth_blt_rb = 0;
6242 device->depth_blt_rb_w = 0;
6243 device->depth_blt_rb_h = 0;
6245 LEAVE_GL();
6247 device->blitter->free_private(device);
6248 device->frag_pipe->free_private(device);
6249 device->shader_backend->shader_free_private(device);
6250 destroy_dummy_textures(device, gl_info);
6252 context_release(context);
6254 while (device->numContexts)
6256 context_destroy(device, device->contexts[0]);
6258 HeapFree(GetProcessHeap(), 0, swapchain->context);
6259 swapchain->context = NULL;
6260 swapchain->num_contexts = 0;
6263 /* Do not call while under the GL lock. */
6264 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6266 struct wined3d_context *context;
6267 HRESULT hr;
6268 IWineD3DSurfaceImpl *target;
6270 /* Recreate the primary swapchain's context */
6271 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6272 if (!swapchain->context)
6274 ERR("Failed to allocate memory for swapchain context array.\n");
6275 return E_OUTOFMEMORY;
6278 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6279 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6281 WARN("Failed to create context.\n");
6282 HeapFree(GetProcessHeap(), 0, swapchain->context);
6283 return E_FAIL;
6286 swapchain->context[0] = context;
6287 swapchain->num_contexts = 1;
6288 create_dummy_textures(device);
6289 context_release(context);
6291 hr = device->shader_backend->shader_alloc_private(device);
6292 if (FAILED(hr))
6294 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6295 goto err;
6298 hr = device->frag_pipe->alloc_private(device);
6299 if (FAILED(hr))
6301 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6302 device->shader_backend->shader_free_private(device);
6303 goto err;
6306 hr = device->blitter->alloc_private(device);
6307 if (FAILED(hr))
6309 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6310 device->frag_pipe->free_private(device);
6311 device->shader_backend->shader_free_private(device);
6312 goto err;
6315 return WINED3D_OK;
6317 err:
6318 context_acquire(device, NULL);
6319 destroy_dummy_textures(device, context->gl_info);
6320 context_release(context);
6321 context_destroy(device, context);
6322 HeapFree(GetProcessHeap(), 0, swapchain->context);
6323 swapchain->num_contexts = 0;
6324 return hr;
6327 /* Do not call while under the GL lock. */
6328 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6329 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 IWineD3DSwapChainImpl *swapchain;
6333 HRESULT hr;
6334 BOOL DisplayModeChanged = FALSE;
6335 WINED3DDISPLAYMODE mode;
6336 TRACE("(%p)\n", This);
6338 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6339 if(FAILED(hr)) {
6340 ERR("Failed to get the first implicit swapchain\n");
6341 return hr;
6344 if(!is_display_mode_supported(This, pPresentationParameters)) {
6345 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6346 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6347 pPresentationParameters->BackBufferHeight);
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6349 return WINED3DERR_INVALIDCALL;
6352 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6353 * on an existing gl context, so there's no real need for recreation.
6355 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6357 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6359 TRACE("New params:\n");
6360 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6361 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6362 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6363 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6364 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6365 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6366 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6367 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6368 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6369 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6370 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6371 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6372 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6374 /* No special treatment of these parameters. Just store them */
6375 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6376 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6377 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6378 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6380 /* What to do about these? */
6381 if (pPresentationParameters->BackBufferCount
6382 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6383 ERR("Cannot change the back buffer count yet\n");
6385 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6386 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6387 ERR("Cannot change the back buffer format yet\n");
6390 if (pPresentationParameters->hDeviceWindow
6391 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6392 ERR("Cannot change the device window yet\n");
6394 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6396 HRESULT hrc;
6398 TRACE("Creating the depth stencil buffer\n");
6400 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6401 pPresentationParameters->BackBufferWidth,
6402 pPresentationParameters->BackBufferHeight,
6403 pPresentationParameters->AutoDepthStencilFormat,
6404 pPresentationParameters->MultiSampleType,
6405 pPresentationParameters->MultiSampleQuality,
6406 FALSE,
6407 (IWineD3DSurface **)&This->auto_depth_stencil);
6409 if (FAILED(hrc)) {
6410 ERR("Failed to create the depth stencil buffer\n");
6411 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6412 return WINED3DERR_INVALIDCALL;
6416 if (This->onscreen_depth_stencil)
6418 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6419 This->onscreen_depth_stencil = NULL;
6422 /* Reset the depth stencil */
6423 if (pPresentationParameters->EnableAutoDepthStencil)
6424 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6425 else
6426 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6428 TRACE("Resetting stateblock\n");
6429 wined3d_stateblock_decref(This->updateStateBlock);
6430 wined3d_stateblock_decref(This->stateBlock);
6432 delete_opengl_contexts(This, swapchain);
6434 if(pPresentationParameters->Windowed) {
6435 mode.Width = swapchain->orig_width;
6436 mode.Height = swapchain->orig_height;
6437 mode.RefreshRate = 0;
6438 mode.Format = swapchain->presentParms.BackBufferFormat;
6439 } else {
6440 mode.Width = pPresentationParameters->BackBufferWidth;
6441 mode.Height = pPresentationParameters->BackBufferHeight;
6442 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6443 mode.Format = swapchain->presentParms.BackBufferFormat;
6446 /* Should Width == 800 && Height == 0 set 800x600? */
6447 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6448 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6449 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6451 UINT i;
6453 if(!pPresentationParameters->Windowed) {
6454 DisplayModeChanged = TRUE;
6456 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6457 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6459 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6460 if(FAILED(hr))
6462 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6463 return hr;
6466 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6468 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6469 if(FAILED(hr))
6471 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6472 return hr;
6475 if (This->auto_depth_stencil)
6477 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6478 if(FAILED(hr))
6480 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6481 return hr;
6486 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6487 || DisplayModeChanged)
6489 BOOL filter = This->filter_messages;
6490 This->filter_messages = TRUE;
6492 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6494 if (!pPresentationParameters->Windowed)
6496 if (swapchain->presentParms.Windowed)
6498 HWND focus_window = This->createParms.hFocusWindow;
6499 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6500 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6502 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6504 return hr;
6507 /* switch from windowed to fs */
6508 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6509 pPresentationParameters->BackBufferWidth,
6510 pPresentationParameters->BackBufferHeight);
6512 else
6514 /* Fullscreen -> fullscreen mode change */
6515 MoveWindow(swapchain->device_window, 0, 0,
6516 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6517 TRUE);
6520 else if (!swapchain->presentParms.Windowed)
6522 /* Fullscreen -> windowed switch */
6523 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6524 IWineD3DDevice_ReleaseFocusWindow(iface);
6526 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6528 This->filter_messages = filter;
6530 else if (!pPresentationParameters->Windowed)
6532 DWORD style = This->style, exStyle = This->exStyle;
6533 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6534 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6535 * Reset to clear up their mess. Guild Wars also loses the device during that.
6537 This->style = 0;
6538 This->exStyle = 0;
6539 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6540 pPresentationParameters->BackBufferWidth,
6541 pPresentationParameters->BackBufferHeight);
6542 This->style = style;
6543 This->exStyle = exStyle;
6546 /* Note: No parent needed for initial internal stateblock */
6547 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, &This->stateBlock);
6548 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6549 else TRACE("Created stateblock %p\n", This->stateBlock);
6550 This->updateStateBlock = This->stateBlock;
6551 wined3d_stateblock_incref(This->updateStateBlock);
6553 stateblock_init_default_state(This->stateBlock);
6555 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6557 RECT client_rect;
6558 GetClientRect(swapchain->win_handle, &client_rect);
6560 if(!swapchain->presentParms.BackBufferCount)
6562 TRACE("Single buffered rendering\n");
6563 swapchain->render_to_fbo = FALSE;
6565 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6566 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6568 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6569 swapchain->presentParms.BackBufferWidth,
6570 swapchain->presentParms.BackBufferHeight,
6571 client_rect.right, client_rect.bottom);
6572 swapchain->render_to_fbo = TRUE;
6574 else
6576 TRACE("Rendering directly to GL_BACK\n");
6577 swapchain->render_to_fbo = FALSE;
6581 hr = create_primary_opengl_context(This, swapchain);
6582 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6584 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6585 * first use
6587 return hr;
6590 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6592 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6594 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6596 return WINED3D_OK;
6600 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6602 TRACE("(%p) : pParameters %p\n", This, pParameters);
6604 *pParameters = This->createParms;
6605 return WINED3D_OK;
6608 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6609 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6611 IWineD3DSwapChain *swapchain;
6613 TRACE("Relaying to swapchain\n");
6615 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6617 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6618 IWineD3DSwapChain_Release(swapchain);
6622 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6623 IWineD3DSwapChain *swapchain;
6625 TRACE("Relaying to swapchain\n");
6627 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6628 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6629 IWineD3DSwapChain_Release(swapchain);
6633 void device_resource_add(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6635 TRACE("device %p, resource %p.\n", device, resource);
6637 list_add_head(&device->resources, &resource->resource.resource_list_entry);
6640 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6642 TRACE("device %p, resource %p.\n", device, resource);
6644 list_remove(&resource->resource.resource_list_entry);
6647 void device_resource_released(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6649 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6650 unsigned int i;
6652 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6654 context_resource_released(device, resource, type);
6656 switch (type)
6658 case WINED3DRTYPE_SURFACE:
6659 if (!device->d3d_initialized) break;
6661 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6663 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6665 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6666 device->render_targets[i] = NULL;
6670 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6672 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6673 device->depth_stencil = NULL;
6675 break;
6677 case WINED3DRTYPE_TEXTURE:
6678 case WINED3DRTYPE_CUBETEXTURE:
6679 case WINED3DRTYPE_VOLUMETEXTURE:
6680 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6682 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6684 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6685 resource, device->stateBlock, i);
6686 device->stateBlock->state.textures[i] = NULL;
6689 if (device->updateStateBlock != device->stateBlock
6690 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6692 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6693 resource, device->updateStateBlock, i);
6694 device->updateStateBlock->state.textures[i] = NULL;
6697 break;
6699 case WINED3DRTYPE_BUFFER:
6700 for (i = 0; i < MAX_STREAMS; ++i)
6702 if (device->stateBlock
6703 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6705 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6706 resource, device->stateBlock, i);
6707 device->stateBlock->state.streams[i].buffer = NULL;
6710 if (device->updateStateBlock != device->stateBlock
6711 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6713 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6714 resource, device->updateStateBlock, i);
6715 device->updateStateBlock->state.streams[i].buffer = NULL;
6720 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6722 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6723 resource, device->stateBlock);
6724 device->stateBlock->state.index_buffer = NULL;
6727 if (device->updateStateBlock != device->stateBlock
6728 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6730 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6731 resource, device->updateStateBlock);
6732 device->updateStateBlock->state.index_buffer = NULL;
6734 break;
6736 default:
6737 break;
6740 /* Remove the resource from the resourceStore */
6741 device_resource_remove(device, resource);
6743 TRACE("Resource released.\n");
6746 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6748 IWineD3DResourceImpl *resource, *cursor;
6749 HRESULT ret;
6750 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6752 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6753 TRACE("enumerating resource %p\n", resource);
6754 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6755 ret = pCallback((IWineD3DResource *) resource, pData);
6756 if(ret == S_FALSE) {
6757 TRACE("Canceling enumeration\n");
6758 break;
6761 return WINED3D_OK;
6764 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6767 IWineD3DResourceImpl *resource;
6769 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6771 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6772 if (type == WINED3DRTYPE_SURFACE)
6774 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6776 TRACE("Found surface %p for dc %p.\n", resource, dc);
6777 *surface = (IWineD3DSurface *)resource;
6778 return WINED3D_OK;
6783 return WINED3DERR_INVALIDCALL;
6786 /**********************************************************
6787 * IWineD3DDevice VTbl follows
6788 **********************************************************/
6790 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6792 /*** IUnknown methods ***/
6793 IWineD3DDeviceImpl_QueryInterface,
6794 IWineD3DDeviceImpl_AddRef,
6795 IWineD3DDeviceImpl_Release,
6796 /*** IWineD3DDevice methods ***/
6797 /*** Creation methods**/
6798 IWineD3DDeviceImpl_CreateBuffer,
6799 IWineD3DDeviceImpl_CreateVertexBuffer,
6800 IWineD3DDeviceImpl_CreateIndexBuffer,
6801 IWineD3DDeviceImpl_CreateStateBlock,
6802 IWineD3DDeviceImpl_CreateSurface,
6803 IWineD3DDeviceImpl_CreateRendertargetView,
6804 IWineD3DDeviceImpl_CreateTexture,
6805 IWineD3DDeviceImpl_CreateVolumeTexture,
6806 IWineD3DDeviceImpl_CreateVolume,
6807 IWineD3DDeviceImpl_CreateCubeTexture,
6808 IWineD3DDeviceImpl_CreateQuery,
6809 IWineD3DDeviceImpl_CreateSwapChain,
6810 IWineD3DDeviceImpl_CreateVertexDeclaration,
6811 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6812 IWineD3DDeviceImpl_CreateVertexShader,
6813 IWineD3DDeviceImpl_CreateGeometryShader,
6814 IWineD3DDeviceImpl_CreatePixelShader,
6815 IWineD3DDeviceImpl_CreatePalette,
6816 /*** Odd functions **/
6817 IWineD3DDeviceImpl_Init3D,
6818 IWineD3DDeviceImpl_InitGDI,
6819 IWineD3DDeviceImpl_Uninit3D,
6820 IWineD3DDeviceImpl_UninitGDI,
6821 IWineD3DDeviceImpl_SetMultithreaded,
6822 IWineD3DDeviceImpl_EvictManagedResources,
6823 IWineD3DDeviceImpl_GetAvailableTextureMem,
6824 IWineD3DDeviceImpl_GetBackBuffer,
6825 IWineD3DDeviceImpl_GetCreationParameters,
6826 IWineD3DDeviceImpl_GetDeviceCaps,
6827 IWineD3DDeviceImpl_GetDirect3D,
6828 IWineD3DDeviceImpl_GetDisplayMode,
6829 IWineD3DDeviceImpl_SetDisplayMode,
6830 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6831 IWineD3DDeviceImpl_GetRasterStatus,
6832 IWineD3DDeviceImpl_GetSwapChain,
6833 IWineD3DDeviceImpl_Reset,
6834 IWineD3DDeviceImpl_SetDialogBoxMode,
6835 IWineD3DDeviceImpl_SetCursorProperties,
6836 IWineD3DDeviceImpl_SetCursorPosition,
6837 IWineD3DDeviceImpl_ShowCursor,
6838 /*** Getters and setters **/
6839 IWineD3DDeviceImpl_SetClipPlane,
6840 IWineD3DDeviceImpl_GetClipPlane,
6841 IWineD3DDeviceImpl_SetClipStatus,
6842 IWineD3DDeviceImpl_GetClipStatus,
6843 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6844 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6845 IWineD3DDeviceImpl_SetDepthStencilSurface,
6846 IWineD3DDeviceImpl_GetDepthStencilSurface,
6847 IWineD3DDeviceImpl_SetGammaRamp,
6848 IWineD3DDeviceImpl_GetGammaRamp,
6849 IWineD3DDeviceImpl_SetIndexBuffer,
6850 IWineD3DDeviceImpl_GetIndexBuffer,
6851 IWineD3DDeviceImpl_SetBaseVertexIndex,
6852 IWineD3DDeviceImpl_GetBaseVertexIndex,
6853 IWineD3DDeviceImpl_SetLight,
6854 IWineD3DDeviceImpl_GetLight,
6855 IWineD3DDeviceImpl_SetLightEnable,
6856 IWineD3DDeviceImpl_GetLightEnable,
6857 IWineD3DDeviceImpl_SetMaterial,
6858 IWineD3DDeviceImpl_GetMaterial,
6859 IWineD3DDeviceImpl_SetNPatchMode,
6860 IWineD3DDeviceImpl_GetNPatchMode,
6861 IWineD3DDeviceImpl_SetPaletteEntries,
6862 IWineD3DDeviceImpl_GetPaletteEntries,
6863 IWineD3DDeviceImpl_SetPixelShader,
6864 IWineD3DDeviceImpl_GetPixelShader,
6865 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6866 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6867 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6868 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6869 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6870 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6871 IWineD3DDeviceImpl_SetRenderState,
6872 IWineD3DDeviceImpl_GetRenderState,
6873 IWineD3DDeviceImpl_SetRenderTarget,
6874 IWineD3DDeviceImpl_GetRenderTarget,
6875 IWineD3DDeviceImpl_SetSamplerState,
6876 IWineD3DDeviceImpl_GetSamplerState,
6877 IWineD3DDeviceImpl_SetScissorRect,
6878 IWineD3DDeviceImpl_GetScissorRect,
6879 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6880 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6881 IWineD3DDeviceImpl_SetStreamSource,
6882 IWineD3DDeviceImpl_GetStreamSource,
6883 IWineD3DDeviceImpl_SetStreamSourceFreq,
6884 IWineD3DDeviceImpl_GetStreamSourceFreq,
6885 IWineD3DDeviceImpl_SetTexture,
6886 IWineD3DDeviceImpl_GetTexture,
6887 IWineD3DDeviceImpl_SetTextureStageState,
6888 IWineD3DDeviceImpl_GetTextureStageState,
6889 IWineD3DDeviceImpl_SetTransform,
6890 IWineD3DDeviceImpl_GetTransform,
6891 IWineD3DDeviceImpl_SetVertexDeclaration,
6892 IWineD3DDeviceImpl_GetVertexDeclaration,
6893 IWineD3DDeviceImpl_SetVertexShader,
6894 IWineD3DDeviceImpl_GetVertexShader,
6895 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6896 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6897 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6898 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6899 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6900 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6901 IWineD3DDeviceImpl_SetViewport,
6902 IWineD3DDeviceImpl_GetViewport,
6903 IWineD3DDeviceImpl_MultiplyTransform,
6904 IWineD3DDeviceImpl_ValidateDevice,
6905 IWineD3DDeviceImpl_ProcessVertices,
6906 /*** State block ***/
6907 IWineD3DDeviceImpl_BeginStateBlock,
6908 IWineD3DDeviceImpl_EndStateBlock,
6909 /*** Scene management ***/
6910 IWineD3DDeviceImpl_BeginScene,
6911 IWineD3DDeviceImpl_EndScene,
6912 IWineD3DDeviceImpl_Present,
6913 IWineD3DDeviceImpl_Clear,
6914 IWineD3DDeviceImpl_ClearRendertargetView,
6915 /*** Drawing ***/
6916 IWineD3DDeviceImpl_SetPrimitiveType,
6917 IWineD3DDeviceImpl_GetPrimitiveType,
6918 IWineD3DDeviceImpl_DrawPrimitive,
6919 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6920 IWineD3DDeviceImpl_DrawPrimitiveUP,
6921 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6922 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6923 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6924 IWineD3DDeviceImpl_DrawRectPatch,
6925 IWineD3DDeviceImpl_DrawTriPatch,
6926 IWineD3DDeviceImpl_DeletePatch,
6927 IWineD3DDeviceImpl_ColorFill,
6928 IWineD3DDeviceImpl_UpdateTexture,
6929 IWineD3DDeviceImpl_UpdateSurface,
6930 IWineD3DDeviceImpl_GetFrontBufferData,
6931 /*** object tracking ***/
6932 IWineD3DDeviceImpl_EnumResources,
6933 IWineD3DDeviceImpl_GetSurfaceFromDC,
6934 IWineD3DDeviceImpl_AcquireFocusWindow,
6935 IWineD3DDeviceImpl_ReleaseFocusWindow,
6936 IWineD3DDeviceImpl_SetupFullscreenWindow,
6937 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6940 HRESULT device_init(IWineD3DDeviceImpl *device, struct wined3d *wined3d,
6941 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6942 IWineD3DDeviceParent *device_parent)
6944 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6945 const struct fragment_pipeline *fragment_pipeline;
6946 struct shader_caps shader_caps;
6947 struct fragment_caps ffp_caps;
6948 WINED3DDISPLAYMODE mode;
6949 unsigned int i;
6950 HRESULT hr;
6952 device->lpVtbl = &IWineD3DDevice_Vtbl;
6953 device->ref = 1;
6954 device->wined3d = wined3d;
6955 wined3d_incref(device->wined3d);
6956 device->adapter = wined3d->adapter_count ? adapter : NULL;
6957 device->device_parent = device_parent;
6958 list_init(&device->resources);
6959 list_init(&device->shaders);
6961 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6963 /* Get the initial screen setup for ddraw. */
6964 hr = wined3d_get_adapter_display_mode(wined3d, adapter_idx, &mode);
6965 if (FAILED(hr))
6967 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6968 wined3d_decref(device->wined3d);
6969 return hr;
6971 device->ddraw_width = mode.Width;
6972 device->ddraw_height = mode.Height;
6973 device->ddraw_format = mode.Format;
6975 /* Save the creation parameters. */
6976 device->createParms.AdapterOrdinal = adapter_idx;
6977 device->createParms.DeviceType = device_type;
6978 device->createParms.hFocusWindow = focus_window;
6979 device->createParms.BehaviorFlags = flags;
6981 device->devType = device_type;
6982 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6984 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6985 device->shader_backend = adapter->shader_backend;
6987 if (device->shader_backend)
6989 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6990 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6991 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6992 device->vs_clipping = shader_caps.VSClipping;
6994 fragment_pipeline = adapter->fragment_pipe;
6995 device->frag_pipe = fragment_pipeline;
6996 if (fragment_pipeline)
6998 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6999 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7001 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7002 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7003 if (FAILED(hr))
7005 ERR("Failed to compile state table, hr %#x.\n", hr);
7006 wined3d_decref(device->wined3d);
7007 return hr;
7010 device->blitter = adapter->blitter;
7012 return WINED3D_OK;
7016 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7017 DWORD rep = This->StateTable[state].representative;
7018 struct wined3d_context *context;
7019 DWORD idx;
7020 BYTE shift;
7021 UINT i;
7023 for(i = 0; i < This->numContexts; i++) {
7024 context = This->contexts[i];
7025 if(isStateDirty(context, rep)) continue;
7027 context->dirtyArray[context->numDirtyEntries++] = rep;
7028 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7029 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7030 context->isStateDirty[idx] |= (1 << shift);
7034 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7036 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7037 *width = context->current_rt->pow2Width;
7038 *height = context->current_rt->pow2Height;
7041 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7043 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7044 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7045 * current context's drawable, which is the size of the back buffer of the swapchain
7046 * the active context belongs to. */
7047 *width = swapchain->presentParms.BackBufferWidth;
7048 *height = swapchain->presentParms.BackBufferHeight;
7051 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7052 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7054 if (device->filter_messages)
7056 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7057 window, message, wparam, lparam);
7058 if (unicode)
7059 return DefWindowProcW(window, message, wparam, lparam);
7060 else
7061 return DefWindowProcA(window, message, wparam, lparam);
7064 if (message == WM_DESTROY)
7066 TRACE("unregister window %p.\n", window);
7067 wined3d_unregister_window(window);
7069 if (device->focus_window == window) device->focus_window = NULL;
7070 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7073 if (unicode)
7074 return CallWindowProcW(proc, window, message, wparam, lparam);
7075 else
7076 return CallWindowProcA(proc, window, message, wparam, lparam);