wined3d: Pass an IWineD3DResourceImpl pointer to device_resource_remove().
[wine.git] / dlls / wined3d / device.c
blob692042067c56644b9765f322a91f42c322994dc5
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 IWineD3DVertexDeclarationImpl *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 IWineD3DStateBlockImpl *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 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
693 ENTER_GL();
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
703 glStencilMask(~0U);
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
716 LEAVE_GL();
717 device_switch_onscreen_ds(device, context, depth_stencil);
718 ENTER_GL();
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
725 glClearDepth(depth);
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
747 if (!clear_rect)
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
754 else
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
760 glClear(clear_mask);
761 checkGLcall("glClear");
763 else
765 RECT current_rect;
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(&current_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
783 continue;
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
791 else
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
798 glClear(clear_mask);
799 checkGLcall("glClear");
803 LEAVE_GL();
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
811 return WINED3D_OK;
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
827 *object = iface;
828 return S_OK;
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
833 *object = NULL;
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
842 return refCount;
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
851 if (!refCount) {
852 UINT i;
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
884 This = NULL;
886 return refCount;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
894 HRESULT hr;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
909 if (FAILED(hr))
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 return hr;
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
921 return WINED3D_OK;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
930 HRESULT hr;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
946 if (!object)
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
955 if (FAILED(hr))
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
959 return hr;
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
974 HRESULT hr;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
980 if (!object)
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
989 parent, parent_ops);
990 if (FAILED(hr))
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
994 return hr;
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1001 return WINED3D_OK;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1009 HRESULT hr;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1012 if(!object)
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1019 if (FAILED(hr))
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1023 return hr;
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1039 HRESULT hr;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054 if (!object)
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1062 if (FAILED(hr))
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1066 return hr;
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1073 return hr;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1085 if (!object)
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1096 return WINED3D_OK;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1105 HRESULT hr;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1112 if (!object)
1114 ERR("Out of memory\n");
1115 *ppTexture = NULL;
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1120 if (FAILED(hr))
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1124 *ppTexture = NULL;
1125 return hr;
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1132 return WINED3D_OK;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1141 HRESULT hr;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1147 if (!object)
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1155 if (FAILED(hr))
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1160 return hr;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1166 return WINED3D_OK;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1175 HRESULT hr;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1181 if (!object)
1183 ERR("Out of memory\n");
1184 *ppVolume = NULL;
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1189 if (FAILED(hr))
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1193 return hr;
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1199 return WINED3D_OK;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1208 HRESULT hr;
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1211 if (!object)
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1219 if (FAILED(hr))
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1224 return hr;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1230 return WINED3D_OK;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1238 HRESULT hr;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1243 if (!object)
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1250 if (FAILED(hr))
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1254 return hr;
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1260 return WINED3D_OK;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1270 HRESULT hr;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1276 if (!object)
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1283 if (FAILED(hr))
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1287 return hr;
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1293 return WINED3D_OK;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1312 return WINED3D_OK;
1313 } else {
1314 TRACE("Swapchain out of range\n");
1315 *pSwapChain = NULL;
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1326 HRESULT hr;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1332 if(!object)
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1339 if (FAILED(hr))
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1343 return hr;
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1349 return WINED3D_OK;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1356 UINT offset;
1357 UINT idx;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1378 ++state->idx;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1399 unsigned int size;
1400 unsigned int idx;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1411 state.offset = 0;
1412 state.idx = 0;
1414 if (has_pos)
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1420 else
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1428 else
1430 switch (num_blends)
1432 case 1:
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 break;
1435 case 2:
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 break;
1438 case 3:
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 break;
1441 case 4:
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 default:
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1450 if (has_blend_idx)
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1457 else
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1472 break;
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1475 break;
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 break;
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1485 *ppVertexElements = state.elements;
1486 return size;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1495 unsigned int size;
1496 DWORD hr;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1505 return hr;
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1515 HRESULT hr;
1517 if (This->vs_selected_mode == SHADER_NONE)
1518 return WINED3DERR_INVALIDCALL;
1520 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1521 if (!object)
1523 ERR("Failed to allocate shader memory.\n");
1524 return E_OUTOFMEMORY;
1527 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1528 if (FAILED(hr))
1530 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1531 HeapFree(GetProcessHeap(), 0, object);
1532 return hr;
1535 TRACE("Created vertex shader %p.\n", object);
1536 *ppVertexShader = (IWineD3DVertexShader *)object;
1538 return WINED3D_OK;
1541 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1542 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1543 void *parent, const struct wined3d_parent_ops *parent_ops,
1544 IWineD3DGeometryShader **shader)
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 struct wined3d_geometryshader *object;
1548 HRESULT hr;
1550 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1551 if (!object)
1553 ERR("Failed to allocate shader memory.\n");
1554 return E_OUTOFMEMORY;
1557 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1558 if (FAILED(hr))
1560 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1561 HeapFree(GetProcessHeap(), 0, object);
1562 return hr;
1565 TRACE("Created geometry shader %p.\n", object);
1566 *shader = (IWineD3DGeometryShader *)object;
1568 return WINED3D_OK;
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1572 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1573 void *parent, const struct wined3d_parent_ops *parent_ops,
1574 IWineD3DPixelShader **ppPixelShader)
1576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1577 IWineD3DPixelShaderImpl *object;
1578 HRESULT hr;
1580 if (This->ps_selected_mode == SHADER_NONE)
1581 return WINED3DERR_INVALIDCALL;
1583 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1584 if (!object)
1586 ERR("Failed to allocate shader memory.\n");
1587 return E_OUTOFMEMORY;
1590 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1591 if (FAILED(hr))
1593 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1594 HeapFree(GetProcessHeap(), 0, object);
1595 return hr;
1598 TRACE("Created pixel shader %p.\n", object);
1599 *ppPixelShader = (IWineD3DPixelShader *)object;
1601 return WINED3D_OK;
1604 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD flags,
1605 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1608 IWineD3DPaletteImpl *object;
1609 HRESULT hr;
1611 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1612 iface, flags, PalEnt, Palette, parent);
1614 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1615 if (!object)
1617 ERR("Failed to allocate palette memory.\n");
1618 return E_OUTOFMEMORY;
1621 hr = wined3d_palette_init(object, This, flags, PalEnt, parent);
1622 if (FAILED(hr))
1624 WARN("Failed to initialize palette, hr %#x.\n", hr);
1625 HeapFree(GetProcessHeap(), 0, object);
1626 return hr;
1629 TRACE("Created palette %p.\n", object);
1630 *Palette = (IWineD3DPalette *)object;
1632 return WINED3D_OK;
1635 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1636 HBITMAP hbm;
1637 BITMAP bm;
1638 HRESULT hr;
1639 HDC dcb = NULL, dcs = NULL;
1640 WINEDDCOLORKEY colorkey;
1642 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1643 if(hbm)
1645 GetObjectA(hbm, sizeof(BITMAP), &bm);
1646 dcb = CreateCompatibleDC(NULL);
1647 if(!dcb) goto out;
1648 SelectObject(dcb, hbm);
1650 else
1652 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1653 * couldn't be loaded
1655 memset(&bm, 0, sizeof(bm));
1656 bm.bmWidth = 32;
1657 bm.bmHeight = 32;
1660 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1661 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1662 &wined3d_null_parent_ops, &This->logo_surface);
1663 if (FAILED(hr))
1665 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1666 goto out;
1669 if(dcb) {
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1679 else
1681 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1686 out:
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1695 unsigned int i;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1701 ENTER_GL();
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1739 LEAVE_GL();
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1745 ENTER_GL();
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1748 LEAVE_GL();
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static LONG fullscreen_style(LONG style)
1755 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1756 style |= WS_POPUP | WS_SYSMENU;
1757 style &= ~(WS_CAPTION | WS_THICKFRAME);
1759 return style;
1762 static LONG fullscreen_exstyle(LONG exstyle)
1764 /* Filter out window decorations. */
1765 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1767 return exstyle;
1770 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1772 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1773 BOOL filter_messages;
1774 LONG style, exstyle;
1776 TRACE("Setting up window %p for fullscreen mode.\n", window);
1778 if (device->style || device->exStyle)
1780 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1781 window, device->style, device->exStyle);
1784 device->style = GetWindowLongW(window, GWL_STYLE);
1785 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1787 style = fullscreen_style(device->style);
1788 exstyle = fullscreen_exstyle(device->exStyle);
1790 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1791 device->style, device->exStyle, style, exstyle);
1793 filter_messages = device->filter_messages;
1794 device->filter_messages = TRUE;
1796 SetWindowLongW(window, GWL_STYLE, style);
1797 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1798 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1800 device->filter_messages = filter_messages;
1803 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1805 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1806 BOOL filter_messages;
1807 LONG style, exstyle;
1809 if (!device->style && !device->exStyle) return;
1811 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1812 window, device->style, device->exStyle);
1814 style = GetWindowLongW(window, GWL_STYLE);
1815 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1817 filter_messages = device->filter_messages;
1818 device->filter_messages = TRUE;
1820 /* Only restore the style if the application didn't modify it during the
1821 * fullscreen phase. Some applications change it before calling Reset()
1822 * when switching between windowed and fullscreen modes (HL2), some
1823 * depend on the original style (Eve Online). */
1824 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1826 SetWindowLongW(window, GWL_STYLE, device->style);
1827 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1829 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1831 device->filter_messages = filter_messages;
1833 /* Delete the old values. */
1834 device->style = 0;
1835 device->exStyle = 0;
1838 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1840 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1842 TRACE("iface %p, window %p.\n", iface, window);
1844 if (!wined3d_register_window(window, device))
1846 ERR("Failed to register window %p.\n", window);
1847 return E_FAIL;
1850 device->focus_window = window;
1851 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1853 return WINED3D_OK;
1856 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1858 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1860 TRACE("iface %p.\n", iface);
1862 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1863 device->focus_window = NULL;
1866 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1867 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1870 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1871 IWineD3DSwapChainImpl *swapchain = NULL;
1872 struct wined3d_context *context;
1873 HRESULT hr;
1874 DWORD state;
1875 unsigned int i;
1877 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1879 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1880 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1882 TRACE("(%p) : Creating stateblock\n", This);
1883 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1884 if (FAILED(hr))
1886 WARN("Failed to create stateblock\n");
1887 goto err_out;
1889 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1890 This->updateStateBlock = This->stateBlock;
1891 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1893 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1894 sizeof(*This->render_targets) * gl_info->limits.buffers);
1896 This->NumberOfPalettes = 1;
1897 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1898 if (!This->palettes || !This->render_targets)
1900 ERR("Out of memory!\n");
1901 hr = E_OUTOFMEMORY;
1902 goto err_out;
1904 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1905 if(!This->palettes[0]) {
1906 ERR("Out of memory!\n");
1907 hr = E_OUTOFMEMORY;
1908 goto err_out;
1910 for (i = 0; i < 256; ++i) {
1911 This->palettes[0][i].peRed = 0xFF;
1912 This->palettes[0][i].peGreen = 0xFF;
1913 This->palettes[0][i].peBlue = 0xFF;
1914 This->palettes[0][i].peFlags = 0xFF;
1916 This->currentPalette = 0;
1918 /* Initialize the texture unit mapping to a 1:1 mapping */
1919 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1921 if (state < gl_info->limits.fragment_samplers)
1923 This->texUnitMap[state] = state;
1924 This->rev_tex_unit_map[state] = state;
1925 } else {
1926 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1927 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1931 /* Setup the implicit swapchain. This also initializes a context. */
1932 TRACE("Creating implicit swapchain\n");
1933 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1934 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1935 if (FAILED(hr))
1937 WARN("Failed to create implicit swapchain\n");
1938 goto err_out;
1941 This->NumberOfSwapChains = 1;
1942 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1943 if(!This->swapchains) {
1944 ERR("Out of memory!\n");
1945 goto err_out;
1947 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1949 if (swapchain->back_buffers && swapchain->back_buffers[0])
1951 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1952 This->render_targets[0] = swapchain->back_buffers[0];
1954 else
1956 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1957 This->render_targets[0] = swapchain->front_buffer;
1959 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1961 /* Depth Stencil support */
1962 This->depth_stencil = This->auto_depth_stencil;
1963 if (This->depth_stencil)
1964 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1966 hr = This->shader_backend->shader_alloc_private(This);
1967 if(FAILED(hr)) {
1968 TRACE("Shader private data couldn't be allocated\n");
1969 goto err_out;
1971 hr = This->frag_pipe->alloc_private(This);
1972 if(FAILED(hr)) {
1973 TRACE("Fragment pipeline private data couldn't be allocated\n");
1974 goto err_out;
1976 hr = This->blitter->alloc_private(This);
1977 if(FAILED(hr)) {
1978 TRACE("Blitter private data couldn't be allocated\n");
1979 goto err_out;
1982 /* Set up some starting GL setup */
1984 /* Setup all the devices defaults */
1985 stateblock_init_default_state(This->stateBlock);
1987 context = context_acquire(This, swapchain->front_buffer);
1989 create_dummy_textures(This);
1991 ENTER_GL();
1993 /* Initialize the current view state */
1994 This->view_ident = 1;
1995 This->contexts[0]->last_was_rhw = 0;
1996 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1997 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1999 switch(wined3d_settings.offscreen_rendering_mode) {
2000 case ORM_FBO:
2001 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2002 break;
2004 case ORM_BACKBUFFER:
2006 if (context_get_current()->aux_buffers > 0)
2008 TRACE("Using auxilliary buffer for offscreen rendering\n");
2009 This->offscreenBuffer = GL_AUX0;
2010 } else {
2011 TRACE("Using back buffer for offscreen rendering\n");
2012 This->offscreenBuffer = GL_BACK;
2017 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2018 LEAVE_GL();
2020 context_release(context);
2022 /* Clear the screen */
2023 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2024 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2025 0x00, 1.0f, 0);
2027 This->d3d_initialized = TRUE;
2029 if(wined3d_settings.logo) {
2030 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2032 This->highest_dirty_ps_const = 0;
2033 This->highest_dirty_vs_const = 0;
2034 return WINED3D_OK;
2036 err_out:
2037 HeapFree(GetProcessHeap(), 0, This->render_targets);
2038 HeapFree(GetProcessHeap(), 0, This->swapchains);
2039 This->NumberOfSwapChains = 0;
2040 if(This->palettes) {
2041 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2042 HeapFree(GetProcessHeap(), 0, This->palettes);
2044 This->NumberOfPalettes = 0;
2045 if(swapchain) {
2046 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2048 if(This->stateBlock) {
2049 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2050 This->stateBlock = NULL;
2052 if (This->blit_priv) {
2053 This->blitter->free_private(This);
2055 if (This->fragment_priv) {
2056 This->frag_pipe->free_private(This);
2058 if (This->shader_priv) {
2059 This->shader_backend->shader_free_private(This);
2061 return hr;
2064 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2065 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2068 IWineD3DSwapChainImpl *swapchain = NULL;
2069 HRESULT hr;
2071 /* Setup the implicit swapchain */
2072 TRACE("Creating implicit swapchain\n");
2073 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2074 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2075 if (FAILED(hr))
2077 WARN("Failed to create implicit swapchain\n");
2078 goto err_out;
2081 This->NumberOfSwapChains = 1;
2082 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2083 if(!This->swapchains) {
2084 ERR("Out of memory!\n");
2085 goto err_out;
2087 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2088 return WINED3D_OK;
2090 err_out:
2091 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2092 return hr;
2095 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2097 IWineD3DResource_UnLoad(resource);
2098 IWineD3DResource_Release(resource);
2099 return WINED3D_OK;
2102 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2103 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2106 const struct wined3d_gl_info *gl_info;
2107 struct wined3d_context *context;
2108 int sampler;
2109 UINT i;
2110 TRACE("(%p)\n", This);
2112 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2114 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2115 * it was created. Thus make sure a context is active for the glDelete* calls
2117 context = context_acquire(This, NULL);
2118 gl_info = context->gl_info;
2120 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2122 /* Unload resources */
2123 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2125 TRACE("Deleting high order patches\n");
2126 for(i = 0; i < PATCHMAP_SIZE; i++) {
2127 struct list *e1, *e2;
2128 struct WineD3DRectPatch *patch;
2129 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2130 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2131 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2135 /* Delete the mouse cursor texture */
2136 if(This->cursorTexture) {
2137 ENTER_GL();
2138 glDeleteTextures(1, &This->cursorTexture);
2139 LEAVE_GL();
2140 This->cursorTexture = 0;
2143 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2144 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2146 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2147 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2150 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2151 * private data, it might contain opengl pointers
2153 if(This->depth_blt_texture) {
2154 ENTER_GL();
2155 glDeleteTextures(1, &This->depth_blt_texture);
2156 LEAVE_GL();
2157 This->depth_blt_texture = 0;
2159 if (This->depth_blt_rb) {
2160 ENTER_GL();
2161 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2162 LEAVE_GL();
2163 This->depth_blt_rb = 0;
2164 This->depth_blt_rb_w = 0;
2165 This->depth_blt_rb_h = 0;
2168 /* Release the update stateblock */
2169 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2170 if(This->updateStateBlock != This->stateBlock)
2171 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2173 This->updateStateBlock = NULL;
2175 { /* because were not doing proper internal refcounts releasing the primary state block
2176 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2177 to set this->stateBlock = NULL; first */
2178 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2179 This->stateBlock = NULL;
2181 /* Release the stateblock */
2182 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2183 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2187 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2188 This->blitter->free_private(This);
2189 This->frag_pipe->free_private(This);
2190 This->shader_backend->shader_free_private(This);
2192 /* Release the buffers (with sanity checks)*/
2193 if (This->onscreen_depth_stencil)
2195 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2196 This->onscreen_depth_stencil = NULL;
2199 if (This->depth_stencil)
2201 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2203 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2205 This->depth_stencil = NULL;
2206 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2207 && ds != This->auto_depth_stencil)
2209 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2213 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2214 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2216 TRACE("Setting rendertarget to NULL\n");
2217 This->render_targets[0] = NULL;
2219 if (This->auto_depth_stencil)
2221 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2223 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2225 This->auto_depth_stencil = NULL;
2228 context_release(context);
2230 for(i=0; i < This->NumberOfSwapChains; i++) {
2231 TRACE("Releasing the implicit swapchain %d\n", i);
2232 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2233 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2237 HeapFree(GetProcessHeap(), 0, This->swapchains);
2238 This->swapchains = NULL;
2239 This->NumberOfSwapChains = 0;
2241 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2242 HeapFree(GetProcessHeap(), 0, This->palettes);
2243 This->palettes = NULL;
2244 This->NumberOfPalettes = 0;
2246 HeapFree(GetProcessHeap(), 0, This->render_targets);
2247 This->render_targets = NULL;
2249 This->d3d_initialized = FALSE;
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2256 unsigned int i;
2258 for(i=0; i < This->NumberOfSwapChains; i++) {
2259 TRACE("Releasing the implicit swapchain %d\n", i);
2260 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2261 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2265 HeapFree(GetProcessHeap(), 0, This->swapchains);
2266 This->swapchains = NULL;
2267 This->NumberOfSwapChains = 0;
2268 return WINED3D_OK;
2271 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2272 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2273 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2275 * There is no way to deactivate thread safety once it is enabled.
2277 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2280 /*For now just store the flag(needed in case of ddraw) */
2281 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2284 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2285 const WINED3DDISPLAYMODE* pMode) {
2286 DEVMODEW devmode;
2287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2288 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2289 LONG ret;
2290 RECT clip_rc;
2292 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2294 /* Resize the screen even without a window:
2295 * The app could have unset it with SetCooperativeLevel, but not called
2296 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2297 * but we don't have any hwnd
2300 memset(&devmode, 0, sizeof(devmode));
2301 devmode.dmSize = sizeof(devmode);
2302 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2303 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2304 devmode.dmPelsWidth = pMode->Width;
2305 devmode.dmPelsHeight = pMode->Height;
2307 devmode.dmDisplayFrequency = pMode->RefreshRate;
2308 if (pMode->RefreshRate)
2309 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2311 /* Only change the mode if necessary */
2312 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2313 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2314 return WINED3D_OK;
2316 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2317 if (ret != DISP_CHANGE_SUCCESSFUL)
2319 if (devmode.dmDisplayFrequency)
2321 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2322 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2323 devmode.dmDisplayFrequency = 0;
2324 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2326 if(ret != DISP_CHANGE_SUCCESSFUL) {
2327 return WINED3DERR_NOTAVAILABLE;
2331 /* Store the new values */
2332 This->ddraw_width = pMode->Width;
2333 This->ddraw_height = pMode->Height;
2334 This->ddraw_format = pMode->Format;
2336 /* And finally clip mouse to our screen */
2337 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2338 ClipCursor(&clip_rc);
2340 return WINED3D_OK;
2343 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 *ppD3D = This->wined3d;
2346 TRACE("Returning %p.\n", *ppD3D);
2347 IWineD3D_AddRef(*ppD3D);
2348 return WINED3D_OK;
2351 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2354 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2355 (This->adapter->TextureRam/(1024*1024)),
2356 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2357 /* return simulated texture memory left */
2358 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2361 /*****
2362 * Get / Set Stream Source
2363 *****/
2364 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2365 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 struct wined3d_stream_state *stream;
2369 IWineD3DBuffer *oldSrc;
2371 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2372 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2374 if (StreamNumber >= MAX_STREAMS) {
2375 WARN("Stream out of range %d\n", StreamNumber);
2376 return WINED3DERR_INVALIDCALL;
2377 } else if(OffsetInBytes & 0x3) {
2378 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2379 return WINED3DERR_INVALIDCALL;
2382 stream = &This->updateStateBlock->state.streams[StreamNumber];
2383 oldSrc = (IWineD3DBuffer *)stream->buffer;
2385 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2387 if (oldSrc == pStreamData
2388 && stream->stride == Stride
2389 && stream->offset == OffsetInBytes)
2391 TRACE("Application is setting the old values over, nothing to do\n");
2392 return WINED3D_OK;
2395 stream->buffer = (struct wined3d_buffer *)pStreamData;
2396 if (pStreamData)
2398 stream->stride = Stride;
2399 stream->offset = OffsetInBytes;
2402 /* Handle recording of state blocks */
2403 if (This->isRecordingState) {
2404 TRACE("Recording... not performing anything\n");
2405 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2406 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2407 return WINED3D_OK;
2410 if (pStreamData)
2412 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2413 IWineD3DBuffer_AddRef(pStreamData);
2415 if (oldSrc)
2417 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2418 IWineD3DBuffer_Release(oldSrc);
2421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2423 return WINED3D_OK;
2426 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2427 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 struct wined3d_stream_state *stream;
2432 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2433 iface, StreamNumber, pStream, pOffset, pStride);
2435 if (StreamNumber >= MAX_STREAMS)
2437 WARN("Stream out of range %d\n", StreamNumber);
2438 return WINED3DERR_INVALIDCALL;
2441 stream = &This->stateBlock->state.streams[StreamNumber];
2442 *pStream = (IWineD3DBuffer *)stream->buffer;
2443 *pStride = stream->stride;
2444 if (pOffset) *pOffset = stream->offset;
2446 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2448 return WINED3D_OK;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 struct wined3d_stream_state *stream;
2454 UINT old_flags, oldFreq;
2456 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2458 /* Verify input at least in d3d9 this is invalid. */
2459 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2461 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2462 return WINED3DERR_INVALIDCALL;
2464 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2466 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2467 return WINED3DERR_INVALIDCALL;
2469 if (!Divider)
2471 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2472 return WINED3DERR_INVALIDCALL;
2475 stream = &This->updateStateBlock->state.streams[StreamNumber];
2476 old_flags = stream->flags;
2477 oldFreq = stream->frequency;
2479 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2480 stream->frequency = Divider & 0x7FFFFF;
2482 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2484 if (stream->frequency != oldFreq || stream->flags != old_flags)
2485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2487 return WINED3D_OK;
2490 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 struct wined3d_stream_state *stream;
2494 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2496 stream = &This->updateStateBlock->state.streams[StreamNumber];
2497 *Divider = stream->flags | stream->frequency;
2499 TRACE("Returning %#x.\n", *Divider);
2501 return WINED3D_OK;
2504 /*****
2505 * Get / Set & Multiply Transform
2506 *****/
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 /* Most of this routine, comments included copied from ddraw tree initially: */
2511 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2513 /* Handle recording of state blocks */
2514 if (This->isRecordingState) {
2515 TRACE("Recording... not performing anything\n");
2516 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2517 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2518 return WINED3D_OK;
2522 * If the new matrix is the same as the current one,
2523 * we cut off any further processing. this seems to be a reasonable
2524 * optimization because as was noticed, some apps (warcraft3 for example)
2525 * tend towards setting the same matrix repeatedly for some reason.
2527 * From here on we assume that the new matrix is different, wherever it matters.
2529 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2531 TRACE("The app is setting the same matrix over again\n");
2532 return WINED3D_OK;
2534 else
2536 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2540 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2541 where ViewMat = Camera space, WorldMat = world space.
2543 In OpenGL, camera and world space is combined into GL_MODELVIEW
2544 matrix. The Projection matrix stay projection matrix.
2547 /* Capture the times we can just ignore the change for now */
2548 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2549 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2550 /* Handled by the state manager */
2553 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2556 return WINED3D_OK;
2560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2561 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2563 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2565 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2567 *matrix = device->stateBlock->state.transforms[state];
2569 return WINED3D_OK;
2572 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2573 const WINED3DMATRIX *mat = NULL;
2574 WINED3DMATRIX temp;
2576 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2577 * below means it will be recorded in a state block change, but it
2578 * works regardless where it is recorded.
2579 * If this is found to be wrong, change to StateBlock.
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2584 if (State <= HIGHEST_TRANSFORMSTATE)
2586 mat = &This->updateStateBlock->state.transforms[State];
2588 else
2590 FIXME("Unhandled transform state!!\n");
2593 multiply_matrix(&temp, mat, pMatrix);
2595 /* Apply change via set transform - will reapply to eg. lights this way */
2596 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2599 /*****
2600 * Get / Set Light
2601 *****/
2602 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2603 you can reference any indexes you want as long as that number max are enabled at any
2604 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2605 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2606 but when recording, just build a chain pretty much of commands to be replayed. */
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2609 float rho;
2610 struct wined3d_light_info *object = NULL;
2611 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2612 struct list *e;
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2617 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2618 * the gl driver.
2620 if(!pLight) {
2621 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2622 return WINED3DERR_INVALIDCALL;
2625 switch(pLight->Type) {
2626 case WINED3DLIGHT_POINT:
2627 case WINED3DLIGHT_SPOT:
2628 case WINED3DLIGHT_PARALLELPOINT:
2629 case WINED3DLIGHT_GLSPOT:
2630 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2631 * most wanted
2633 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2635 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2636 return WINED3DERR_INVALIDCALL;
2638 break;
2640 case WINED3DLIGHT_DIRECTIONAL:
2641 /* Ignores attenuation */
2642 break;
2644 default:
2645 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2646 return WINED3DERR_INVALIDCALL;
2649 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2651 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2652 if(object->OriginalIndex == Index) break;
2653 object = NULL;
2656 if(!object) {
2657 TRACE("Adding new light\n");
2658 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2659 if(!object) {
2660 ERR("Out of memory error when allocating a light\n");
2661 return E_OUTOFMEMORY;
2663 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2664 object->glIndex = -1;
2665 object->OriginalIndex = Index;
2668 /* Initialize the object */
2669 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,
2670 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2671 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2672 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2673 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2674 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2675 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2677 /* Save away the information */
2678 object->OriginalParms = *pLight;
2680 switch (pLight->Type) {
2681 case WINED3DLIGHT_POINT:
2682 /* Position */
2683 object->lightPosn[0] = pLight->Position.x;
2684 object->lightPosn[1] = pLight->Position.y;
2685 object->lightPosn[2] = pLight->Position.z;
2686 object->lightPosn[3] = 1.0f;
2687 object->cutoff = 180.0f;
2688 /* FIXME: Range */
2689 break;
2691 case WINED3DLIGHT_DIRECTIONAL:
2692 /* Direction */
2693 object->lightPosn[0] = -pLight->Direction.x;
2694 object->lightPosn[1] = -pLight->Direction.y;
2695 object->lightPosn[2] = -pLight->Direction.z;
2696 object->lightPosn[3] = 0.0f;
2697 object->exponent = 0.0f;
2698 object->cutoff = 180.0f;
2699 break;
2701 case WINED3DLIGHT_SPOT:
2702 /* Position */
2703 object->lightPosn[0] = pLight->Position.x;
2704 object->lightPosn[1] = pLight->Position.y;
2705 object->lightPosn[2] = pLight->Position.z;
2706 object->lightPosn[3] = 1.0f;
2708 /* Direction */
2709 object->lightDirn[0] = pLight->Direction.x;
2710 object->lightDirn[1] = pLight->Direction.y;
2711 object->lightDirn[2] = pLight->Direction.z;
2712 object->lightDirn[3] = 1.0f;
2715 * opengl-ish and d3d-ish spot lights use too different models for the
2716 * light "intensity" as a function of the angle towards the main light direction,
2717 * so we only can approximate very roughly.
2718 * however spot lights are rather rarely used in games (if ever used at all).
2719 * furthermore if still used, probably nobody pays attention to such details.
2721 if (!pLight->Falloff)
2723 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2724 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2725 * will always be 1.0 for both of them, and we don't have to care for the
2726 * rest of the rather complex calculation
2728 object->exponent = 0.0f;
2729 } else {
2730 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2731 if (rho < 0.0001f) rho = 0.0001f;
2732 object->exponent = -0.3f/logf(cosf(rho/2));
2734 if (object->exponent > 128.0f)
2736 object->exponent = 128.0f;
2738 object->cutoff = (float) (pLight->Phi*90/M_PI);
2740 /* FIXME: Range */
2741 break;
2743 default:
2744 FIXME("Unrecognized light type %d\n", pLight->Type);
2747 /* Update the live definitions if the light is currently assigned a glIndex */
2748 if (object->glIndex != -1 && !This->isRecordingState) {
2749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2751 return WINED3D_OK;
2754 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2756 struct wined3d_light_info *lightInfo = NULL;
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2759 struct list *e;
2760 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2762 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2764 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2765 if(lightInfo->OriginalIndex == Index) break;
2766 lightInfo = NULL;
2769 if (!lightInfo)
2771 TRACE("Light information requested but light not defined\n");
2772 return WINED3DERR_INVALIDCALL;
2775 *pLight = lightInfo->OriginalParms;
2776 return WINED3D_OK;
2779 /*****
2780 * Get / Set Light Enable
2781 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2782 *****/
2783 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2785 struct wined3d_light_info *lightInfo = NULL;
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2788 struct list *e;
2789 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2791 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2793 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2794 if(lightInfo->OriginalIndex == Index) break;
2795 lightInfo = NULL;
2797 TRACE("Found light: %p\n", lightInfo);
2799 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2800 if (!lightInfo)
2802 TRACE("Light enabled requested but light not defined, so defining one!\n");
2803 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2805 /* Search for it again! Should be fairly quick as near head of list */
2806 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2808 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2809 if(lightInfo->OriginalIndex == Index) break;
2810 lightInfo = NULL;
2812 if (!lightInfo)
2814 FIXME("Adding default lights has failed dismally\n");
2815 return WINED3DERR_INVALIDCALL;
2819 if(!Enable) {
2820 if(lightInfo->glIndex != -1) {
2821 if(!This->isRecordingState) {
2822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2825 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2826 lightInfo->glIndex = -1;
2827 } else {
2828 TRACE("Light already disabled, nothing to do\n");
2830 lightInfo->enabled = FALSE;
2831 } else {
2832 lightInfo->enabled = TRUE;
2833 if (lightInfo->glIndex != -1) {
2834 /* nop */
2835 TRACE("Nothing to do as light was enabled\n");
2836 } else {
2837 int i;
2838 /* Find a free gl light */
2839 for (i = 0; i < This->maxConcurrentLights; ++i)
2841 if (!This->updateStateBlock->state.lights[i])
2843 This->updateStateBlock->state.lights[i] = lightInfo;
2844 lightInfo->glIndex = i;
2845 break;
2848 if(lightInfo->glIndex == -1) {
2849 /* Our tests show that Windows returns D3D_OK in this situation, even with
2850 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2851 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2852 * as well for those lights.
2854 * TODO: Test how this affects rendering
2856 WARN("Too many concurrently active lights\n");
2857 return WINED3D_OK;
2860 /* i == lightInfo->glIndex */
2861 if(!This->isRecordingState) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2867 return WINED3D_OK;
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2872 struct wined3d_light_info *lightInfo = NULL;
2873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2874 struct list *e;
2875 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2876 TRACE("(%p) : for idx(%d)\n", This, Index);
2878 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2880 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2881 if(lightInfo->OriginalIndex == Index) break;
2882 lightInfo = NULL;
2885 if (!lightInfo)
2887 TRACE("Light enabled state requested but light not defined\n");
2888 return WINED3DERR_INVALIDCALL;
2890 /* true is 128 according to SetLightEnable */
2891 *pEnable = lightInfo->enabled ? 128 : 0;
2892 return WINED3D_OK;
2895 /*****
2896 * Get / Set Clip Planes
2897 *****/
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2902 /* Validate Index */
2903 if (Index >= This->adapter->gl_info.limits.clipplanes)
2905 TRACE("Application has requested clipplane this device doesn't support\n");
2906 return WINED3DERR_INVALIDCALL;
2909 This->updateStateBlock->changed.clipplane |= 1 << Index;
2911 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2912 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2913 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2914 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2916 TRACE("Application is setting old values over, nothing to do\n");
2917 return WINED3D_OK;
2920 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2921 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2922 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2923 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2925 /* Handle recording of state blocks */
2926 if (This->isRecordingState) {
2927 TRACE("Recording... not performing anything\n");
2928 return WINED3D_OK;
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 TRACE("(%p) : for idx %d\n", This, Index);
2940 /* Validate Index */
2941 if (Index >= This->adapter->gl_info.limits.clipplanes)
2943 TRACE("Application has requested clipplane this device doesn't support\n");
2944 return WINED3DERR_INVALIDCALL;
2947 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2948 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2949 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2950 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2951 return WINED3D_OK;
2954 /*****
2955 * Get / Set Clip Plane Status
2956 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2957 *****/
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 FIXME("(%p) : stub\n", This);
2962 if (!pClipStatus)
2963 return WINED3DERR_INVALIDCALL;
2965 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2966 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 FIXME("(%p) : stub\n", This);
2974 if (!pClipStatus)
2975 return WINED3DERR_INVALIDCALL;
2977 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2978 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2979 return WINED3D_OK;
2982 /*****
2983 * Get / Set Material
2984 *****/
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 This->updateStateBlock->changed.material = TRUE;
2989 This->updateStateBlock->state.material = *pMaterial;
2991 /* Handle recording of state blocks */
2992 if (This->isRecordingState) {
2993 TRACE("Recording... not performing anything\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 *pMaterial = This->updateStateBlock->state.material;
3004 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3005 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3006 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3007 pMaterial->Ambient.b, pMaterial->Ambient.a);
3008 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3009 pMaterial->Specular.b, pMaterial->Specular.a);
3010 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3011 pMaterial->Emissive.b, pMaterial->Emissive.a);
3012 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3014 return WINED3D_OK;
3017 /*****
3018 * Get / Set Indices
3019 *****/
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3021 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 IWineD3DBuffer *oldIdxs;
3026 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3027 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3029 This->updateStateBlock->changed.indices = TRUE;
3030 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3031 This->updateStateBlock->state.index_format = fmt;
3033 /* Handle recording of state blocks */
3034 if (This->isRecordingState) {
3035 TRACE("Recording... not performing anything\n");
3036 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3037 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3038 return WINED3D_OK;
3041 if(oldIdxs != pIndexData) {
3042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3043 if(pIndexData) {
3044 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3045 IWineD3DBuffer_AddRef(pIndexData);
3047 if(oldIdxs) {
3048 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3049 IWineD3DBuffer_Release(oldIdxs);
3053 return WINED3D_OK;
3056 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3062 /* up ref count on ppindexdata */
3063 if (*ppIndexData) {
3064 IWineD3DBuffer_AddRef(*ppIndexData);
3065 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3066 }else{
3067 TRACE("(%p) No index data set\n", This);
3069 TRACE("Returning %p\n", *ppIndexData);
3071 return WINED3D_OK;
3074 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3075 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 TRACE("(%p)->(%d)\n", This, BaseIndex);
3079 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3081 TRACE("Application is setting the old value over, nothing to do\n");
3082 return WINED3D_OK;
3085 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3087 if (This->isRecordingState) {
3088 TRACE("Recording... not performing anything\n");
3089 return WINED3D_OK;
3091 /* The base vertex index affects the stream sources */
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 TRACE("(%p) : base_index %p\n", This, base_index);
3100 *base_index = This->stateBlock->state.base_vertex_index;
3102 TRACE("Returning %u\n", *base_index);
3104 return WINED3D_OK;
3107 /*****
3108 * Get / Set Viewports
3109 *****/
3110 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3113 TRACE("(%p)\n", This);
3114 This->updateStateBlock->changed.viewport = TRUE;
3115 This->updateStateBlock->state.viewport = *pViewport;
3117 /* Handle recording of state blocks */
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3123 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3124 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3127 return WINED3D_OK;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 TRACE("(%p)\n", This);
3134 *pViewport = This->stateBlock->state.viewport;
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3139 WINED3DRENDERSTATETYPE State, DWORD Value)
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 DWORD oldValue = This->stateBlock->state.render_states[State];
3144 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3146 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3147 This->updateStateBlock->state.render_states[State] = Value;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3152 return WINED3D_OK;
3155 /* Compared here and not before the assignment to allow proper stateblock recording */
3156 if(Value == oldValue) {
3157 TRACE("Application is setting the old value over, nothing to do\n");
3158 } else {
3159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3162 return WINED3D_OK;
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3166 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3172 *pValue = This->stateBlock->state.render_states[State];
3173 return WINED3D_OK;
3176 /*****
3177 * Get / Set Sampler States
3178 * TODO: Verify against dx9 definitions
3179 *****/
3181 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 DWORD oldValue;
3185 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3186 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3188 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3189 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3192 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3194 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3195 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3198 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3199 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3200 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3202 /* Handle recording of state blocks */
3203 if (This->isRecordingState) {
3204 TRACE("Recording... not performing anything\n");
3205 return WINED3D_OK;
3208 if(oldValue == Value) {
3209 TRACE("Application is setting the old value over, nothing to do\n");
3210 return WINED3D_OK;
3213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3215 return WINED3D_OK;
3218 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3222 This, Sampler, debug_d3dsamplerstate(Type), Type);
3224 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3225 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3228 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3230 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3231 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3233 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3234 TRACE("(%p) : Returning %#x\n", This, *Value);
3236 return WINED3D_OK;
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 This->updateStateBlock->changed.scissorRect = TRUE;
3243 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3245 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3246 return WINED3D_OK;
3248 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3250 if(This->isRecordingState) {
3251 TRACE("Recording... not performing anything\n");
3252 return WINED3D_OK;
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 *pRect = This->updateStateBlock->state.scissor_rect;
3264 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3265 return WINED3D_OK;
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3270 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3272 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3274 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3275 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3277 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3278 This->updateStateBlock->changed.vertexDecl = TRUE;
3280 if (This->isRecordingState) {
3281 TRACE("Recording... not performing anything\n");
3282 return WINED3D_OK;
3283 } else if(pDecl == oldDecl) {
3284 /* Checked after the assignment to allow proper stateblock recording */
3285 TRACE("Application is setting the old declaration over, nothing to do\n");
3286 return WINED3D_OK;
3289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3290 return WINED3D_OK;
3293 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3298 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3299 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3300 return WINED3D_OK;
3303 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3308 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3309 This->updateStateBlock->changed.vertexShader = TRUE;
3311 if (This->isRecordingState) {
3312 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3313 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3314 TRACE("Recording... not performing anything\n");
3315 return WINED3D_OK;
3316 } else if(oldShader == pShader) {
3317 /* Checked here to allow proper stateblock recording */
3318 TRACE("App is setting the old shader over, nothing to do\n");
3319 return WINED3D_OK;
3322 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3323 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3324 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3328 return WINED3D_OK;
3331 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3333 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3334 IWineD3DVertexShader *shader;
3336 TRACE("iface %p.\n", iface);
3338 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3339 if (shader) IWineD3DVertexShader_AddRef(shader);
3341 TRACE("Returning %p.\n", shader);
3342 return shader;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3346 IWineD3DDevice *iface,
3347 UINT start,
3348 CONST BOOL *srcData,
3349 UINT count) {
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3354 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3355 iface, srcData, start, count);
3357 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3359 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3360 for (i = 0; i < cnt; i++)
3361 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3363 for (i = start; i < cnt + start; ++i) {
3364 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3367 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3369 return WINED3D_OK;
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3373 IWineD3DDevice *iface,
3374 UINT start,
3375 BOOL *dstData,
3376 UINT count) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 int cnt = min(count, MAX_CONST_B - start);
3381 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3382 iface, dstData, start, count);
3384 if (!dstData || cnt < 0)
3385 return WINED3DERR_INVALIDCALL;
3387 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3388 return WINED3D_OK;
3391 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3392 IWineD3DDevice *iface,
3393 UINT start,
3394 CONST int *srcData,
3395 UINT count) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3400 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3401 iface, srcData, start, count);
3403 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3405 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3406 for (i = 0; i < cnt; i++)
3407 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3408 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3410 for (i = start; i < cnt + start; ++i) {
3411 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3414 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3416 return WINED3D_OK;
3419 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3420 IWineD3DDevice *iface,
3421 UINT start,
3422 int *dstData,
3423 UINT count) {
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 int cnt = min(count, MAX_CONST_I - start);
3428 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3429 iface, dstData, start, count);
3431 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3432 return WINED3DERR_INVALIDCALL;
3434 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3435 return WINED3D_OK;
3438 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3439 IWineD3DDevice *iface,
3440 UINT start,
3441 CONST float *srcData,
3442 UINT count) {
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 UINT i;
3447 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3448 iface, srcData, start, count);
3450 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3451 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3452 return WINED3DERR_INVALIDCALL;
3454 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3455 if(TRACE_ON(d3d)) {
3456 for (i = 0; i < count; i++)
3457 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3458 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3461 if (!This->isRecordingState)
3463 This->shader_backend->shader_update_float_vertex_constants(This, start, count);
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3467 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3468 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3470 return WINED3D_OK;
3473 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3474 IWineD3DDevice *iface,
3475 UINT start,
3476 float *dstData,
3477 UINT count) {
3479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 int cnt = min(count, This->d3d_vshader_constantF - start);
3482 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3483 iface, dstData, start, count);
3485 if (!dstData || cnt < 0)
3486 return WINED3DERR_INVALIDCALL;
3488 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3489 return WINED3D_OK;
3492 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3493 DWORD i;
3494 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3500 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3502 DWORD i = This->rev_tex_unit_map[unit];
3503 DWORD j = This->texUnitMap[stage];
3505 This->texUnitMap[stage] = unit;
3506 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3508 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3511 This->rev_tex_unit_map[unit] = stage;
3512 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3514 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3518 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3519 int i;
3521 This->fixed_function_usage_map = 0;
3522 for (i = 0; i < MAX_TEXTURES; ++i)
3524 const struct wined3d_state *state = &This->stateBlock->state;
3525 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3526 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3527 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3528 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3529 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3530 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3531 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3532 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3534 if (color_op == WINED3DTOP_DISABLE) {
3535 /* Not used, and disable higher stages */
3536 break;
3539 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3540 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3541 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3542 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3543 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3544 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3545 This->fixed_function_usage_map |= (1 << i);
3548 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3549 This->fixed_function_usage_map |= (1 << (i + 1));
3554 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3556 unsigned int i, tex;
3557 WORD ffu_map;
3559 device_update_fixed_function_usage_map(This);
3560 ffu_map = This->fixed_function_usage_map;
3562 if (This->max_ffp_textures == gl_info->limits.texture_stages
3563 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3565 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3567 if (!(ffu_map & 1)) continue;
3569 if (This->texUnitMap[i] != i) {
3570 device_map_stage(This, i, i);
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3572 markTextureStagesDirty(This, i);
3575 return;
3578 /* Now work out the mapping */
3579 tex = 0;
3580 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3582 if (!(ffu_map & 1)) continue;
3584 if (This->texUnitMap[i] != tex) {
3585 device_map_stage(This, i, tex);
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3587 markTextureStagesDirty(This, i);
3590 ++tex;
3594 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3596 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3597 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3598 unsigned int i;
3600 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3601 if (sampler_type[i] && This->texUnitMap[i] != i)
3603 device_map_stage(This, i, i);
3604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3605 if (i < gl_info->limits.texture_stages)
3607 markTextureStagesDirty(This, i);
3613 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3614 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3616 DWORD current_mapping = This->rev_tex_unit_map[unit];
3618 /* Not currently used */
3619 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3621 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3622 /* Used by a fragment sampler */
3624 if (!pshader_sampler_tokens) {
3625 /* No pixel shader, check fixed function */
3626 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3629 /* Pixel shader, check the shader's sampler map */
3630 return !pshader_sampler_tokens[current_mapping];
3633 /* Used by a vertex sampler */
3634 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3637 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3639 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3640 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3641 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3642 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3643 int i;
3645 if (ps)
3647 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3649 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3650 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3651 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3654 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3655 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3656 if (vshader_sampler_type[i])
3658 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3660 /* Already mapped somewhere */
3661 continue;
3664 while (start >= 0) {
3665 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3667 device_map_stage(This, vsampler_idx, start);
3668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3670 --start;
3671 break;
3674 --start;
3680 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3682 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3683 const struct wined3d_state *state = &This->stateBlock->state;
3684 BOOL vs = use_vs(state);
3685 BOOL ps = use_ps(state);
3687 * Rules are:
3688 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3689 * that would be really messy and require shader recompilation
3690 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3691 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3693 if (ps) device_map_psamplers(This, gl_info);
3694 else device_map_fixed_function_samplers(This, gl_info);
3696 if (vs) device_map_vsamplers(This, ps, gl_info);
3699 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3703 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3704 This->updateStateBlock->changed.pixelShader = TRUE;
3706 /* Handle recording of state blocks */
3707 if (This->isRecordingState) {
3708 TRACE("Recording... not performing anything\n");
3711 if (This->isRecordingState) {
3712 TRACE("Recording... not performing anything\n");
3713 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3714 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3715 return WINED3D_OK;
3718 if(pShader == oldShader) {
3719 TRACE("App is setting the old pixel shader over, nothing to do\n");
3720 return WINED3D_OK;
3723 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3724 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3726 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3729 return WINED3D_OK;
3732 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3734 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3735 IWineD3DPixelShader *shader;
3737 TRACE("iface %p.\n", iface);
3739 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3740 if (shader) IWineD3DPixelShader_AddRef(shader);
3742 TRACE("Returning %p.\n", shader);
3743 return shader;
3746 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3747 IWineD3DDevice *iface,
3748 UINT start,
3749 CONST BOOL *srcData,
3750 UINT count) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3755 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3756 iface, srcData, start, count);
3758 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3760 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3761 for (i = 0; i < cnt; i++)
3762 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3764 for (i = start; i < cnt + start; ++i) {
3765 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3768 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3770 return WINED3D_OK;
3773 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3774 IWineD3DDevice *iface,
3775 UINT start,
3776 BOOL *dstData,
3777 UINT count) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 int cnt = min(count, MAX_CONST_B - start);
3782 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3783 iface, dstData, start, count);
3785 if (!dstData || cnt < 0)
3786 return WINED3DERR_INVALIDCALL;
3788 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3789 return WINED3D_OK;
3792 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3793 IWineD3DDevice *iface,
3794 UINT start,
3795 CONST int *srcData,
3796 UINT count) {
3798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3799 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3801 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3802 iface, srcData, start, count);
3804 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3806 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3807 for (i = 0; i < cnt; i++)
3808 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3809 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3811 for (i = start; i < cnt + start; ++i) {
3812 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3815 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3817 return WINED3D_OK;
3820 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3821 IWineD3DDevice *iface,
3822 UINT start,
3823 int *dstData,
3824 UINT count) {
3826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3827 int cnt = min(count, MAX_CONST_I - start);
3829 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3830 iface, dstData, start, count);
3832 if (!dstData || cnt < 0)
3833 return WINED3DERR_INVALIDCALL;
3835 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3836 return WINED3D_OK;
3839 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3840 IWineD3DDevice *iface,
3841 UINT start,
3842 CONST float *srcData,
3843 UINT count) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 UINT i;
3848 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3849 iface, srcData, start, count);
3851 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3852 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3853 return WINED3DERR_INVALIDCALL;
3855 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3856 if(TRACE_ON(d3d)) {
3857 for (i = 0; i < count; i++)
3858 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3859 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3862 if (!This->isRecordingState)
3864 This->shader_backend->shader_update_float_pixel_constants(This, start, count);
3865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3868 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3869 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3875 IWineD3DDevice *iface,
3876 UINT start,
3877 float *dstData,
3878 UINT count) {
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 int cnt = min(count, This->d3d_pshader_constantF - start);
3883 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3884 iface, dstData, start, count);
3886 if (!dstData || cnt < 0)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3890 return WINED3D_OK;
3893 /* Context activation is done by the caller. */
3894 /* Do not call while under the GL lock. */
3895 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3896 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3897 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3898 DWORD DestFVF)
3900 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3901 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3902 unsigned int i;
3903 WINED3DVIEWPORT vp;
3904 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3905 BOOL doClip;
3906 DWORD numTextures;
3908 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3910 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3913 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3915 ERR("Source has no position mask\n");
3916 return WINED3DERR_INVALIDCALL;
3919 if (!dest->resource.allocatedMemory)
3920 buffer_get_sysmem(dest, gl_info);
3922 /* Get a pointer into the destination vbo(create one if none exists) and
3923 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3925 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3927 dest->flags |= WINED3D_BUFFER_CREATEBO;
3928 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3931 if (dest->buffer_object)
3933 unsigned char extrabytes = 0;
3934 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3935 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3936 * this may write 4 extra bytes beyond the area that should be written
3938 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3939 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3940 if(!dest_conv_addr) {
3941 ERR("Out of memory\n");
3942 /* Continue without storing converted vertices */
3944 dest_conv = dest_conv_addr;
3947 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3949 static BOOL warned = FALSE;
3951 * The clipping code is not quite correct. Some things need
3952 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3953 * so disable clipping for now.
3954 * (The graphics in Half-Life are broken, and my processvertices
3955 * test crashes with IDirect3DDevice3)
3956 doClip = TRUE;
3958 doClip = FALSE;
3959 if(!warned) {
3960 warned = TRUE;
3961 FIXME("Clipping is broken and disabled for now\n");
3963 } else doClip = FALSE;
3964 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3966 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3967 WINED3DTS_VIEW,
3968 &view_mat);
3969 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3970 WINED3DTS_PROJECTION,
3971 &proj_mat);
3972 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3973 WINED3DTS_WORLDMATRIX(0),
3974 &world_mat);
3976 TRACE("View mat:\n");
3977 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);
3978 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);
3979 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);
3980 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);
3982 TRACE("Proj mat:\n");
3983 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);
3984 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);
3985 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);
3986 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);
3988 TRACE("World mat:\n");
3989 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);
3990 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);
3991 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);
3992 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);
3994 /* Get the viewport */
3995 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3996 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3997 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3999 multiply_matrix(&mat,&view_mat,&world_mat);
4000 multiply_matrix(&mat,&proj_mat,&mat);
4002 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4004 for (i = 0; i < dwCount; i+= 1) {
4005 unsigned int tex_index;
4007 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4008 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4009 /* The position first */
4010 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4011 const float *p = (const float *)(element->data + i * element->stride);
4012 float x, y, z, rhw;
4013 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4015 /* Multiplication with world, view and projection matrix */
4016 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);
4017 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);
4018 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);
4019 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);
4021 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4023 /* WARNING: The following things are taken from d3d7 and were not yet checked
4024 * against d3d8 or d3d9!
4027 /* Clipping conditions: From msdn
4029 * A vertex is clipped if it does not match the following requirements
4030 * -rhw < x <= rhw
4031 * -rhw < y <= rhw
4032 * 0 < z <= rhw
4033 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4035 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4036 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4040 if( !doClip ||
4041 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4042 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4043 ( rhw > eps ) ) ) {
4045 /* "Normal" viewport transformation (not clipped)
4046 * 1) The values are divided by rhw
4047 * 2) The y axis is negative, so multiply it with -1
4048 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4049 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4050 * 4) Multiply x with Width/2 and add Width/2
4051 * 5) The same for the height
4052 * 6) Add the viewpoint X and Y to the 2D coordinates and
4053 * The minimum Z value to z
4054 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4056 * Well, basically it's simply a linear transformation into viewport
4057 * coordinates
4060 x /= rhw;
4061 y /= rhw;
4062 z /= rhw;
4064 y *= -1;
4066 x *= vp.Width / 2;
4067 y *= vp.Height / 2;
4068 z *= vp.MaxZ - vp.MinZ;
4070 x += vp.Width / 2 + vp.X;
4071 y += vp.Height / 2 + vp.Y;
4072 z += vp.MinZ;
4074 rhw = 1 / rhw;
4075 } else {
4076 /* That vertex got clipped
4077 * Contrary to OpenGL it is not dropped completely, it just
4078 * undergoes a different calculation.
4080 TRACE("Vertex got clipped\n");
4081 x += rhw;
4082 y += rhw;
4084 x /= 2;
4085 y /= 2;
4087 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4088 * outside of the main vertex buffer memory. That needs some more
4089 * investigation...
4093 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4096 ( (float *) dest_ptr)[0] = x;
4097 ( (float *) dest_ptr)[1] = y;
4098 ( (float *) dest_ptr)[2] = z;
4099 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4101 dest_ptr += 3 * sizeof(float);
4103 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4104 dest_ptr += sizeof(float);
4107 if(dest_conv) {
4108 float w = 1 / rhw;
4109 ( (float *) dest_conv)[0] = x * w;
4110 ( (float *) dest_conv)[1] = y * w;
4111 ( (float *) dest_conv)[2] = z * w;
4112 ( (float *) dest_conv)[3] = w;
4114 dest_conv += 3 * sizeof(float);
4116 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4117 dest_conv += sizeof(float);
4121 if (DestFVF & WINED3DFVF_PSIZE) {
4122 dest_ptr += sizeof(DWORD);
4123 if(dest_conv) dest_conv += sizeof(DWORD);
4125 if (DestFVF & WINED3DFVF_NORMAL) {
4126 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4127 const float *normal = (const float *)(element->data + i * element->stride);
4128 /* AFAIK this should go into the lighting information */
4129 FIXME("Didn't expect the destination to have a normal\n");
4130 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4131 if(dest_conv) {
4132 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4136 if (DestFVF & WINED3DFVF_DIFFUSE) {
4137 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4138 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4139 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4141 static BOOL warned = FALSE;
4143 if(!warned) {
4144 ERR("No diffuse color in source, but destination has one\n");
4145 warned = TRUE;
4148 *( (DWORD *) dest_ptr) = 0xffffffff;
4149 dest_ptr += sizeof(DWORD);
4151 if(dest_conv) {
4152 *( (DWORD *) dest_conv) = 0xffffffff;
4153 dest_conv += sizeof(DWORD);
4156 else {
4157 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4158 if(dest_conv) {
4159 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4160 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4161 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4162 dest_conv += sizeof(DWORD);
4167 if (DestFVF & WINED3DFVF_SPECULAR)
4169 /* What's the color value in the feedback buffer? */
4170 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4171 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4172 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4174 static BOOL warned = FALSE;
4176 if(!warned) {
4177 ERR("No specular color in source, but destination has one\n");
4178 warned = TRUE;
4181 *( (DWORD *) dest_ptr) = 0xFF000000;
4182 dest_ptr += sizeof(DWORD);
4184 if(dest_conv) {
4185 *( (DWORD *) dest_conv) = 0xFF000000;
4186 dest_conv += sizeof(DWORD);
4189 else {
4190 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4191 if(dest_conv) {
4192 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4193 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4194 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4195 dest_conv += sizeof(DWORD);
4200 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4201 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4202 const float *tex_coord = (const float *)(element->data + i * element->stride);
4203 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4205 ERR("No source texture, but destination requests one\n");
4206 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4207 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4209 else {
4210 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4211 if(dest_conv) {
4212 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4218 if (dest_conv)
4220 ENTER_GL();
4222 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4223 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4224 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4225 dwCount * get_flexible_vertex_size(DestFVF),
4226 dest_conv_addr));
4227 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4229 LEAVE_GL();
4231 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4234 return WINED3D_OK;
4236 #undef copy_and_next
4238 /* Do not call while under the GL lock. */
4239 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4240 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD flags,
4241 DWORD DestFVF)
4243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4244 struct wined3d_stream_info stream_info;
4245 const struct wined3d_gl_info *gl_info;
4246 struct wined3d_context *context;
4247 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4248 HRESULT hr;
4250 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4252 if(pVertexDecl) {
4253 ERR("Output vertex declaration not implemented yet\n");
4256 /* Need any context to write to the vbo. */
4257 context = context_acquire(This, NULL);
4258 gl_info = context->gl_info;
4260 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4261 * control the streamIsUP flag, thus restore it afterwards.
4263 This->stateBlock->state.user_stream = FALSE;
4264 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4265 This->stateBlock->state.user_stream = streamWasUP;
4267 if(vbo || SrcStartIndex) {
4268 unsigned int i;
4269 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4270 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4272 * Also get the start index in, but only loop over all elements if there's something to add at all.
4274 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4276 struct wined3d_stream_info_element *e;
4278 if (!(stream_info.use_map & (1 << i))) continue;
4280 e = &stream_info.elements[i];
4281 if (e->buffer_object)
4283 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4284 e->buffer_object = 0;
4285 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4286 ENTER_GL();
4287 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4288 vb->buffer_object = 0;
4289 LEAVE_GL();
4291 if (e->data) e->data += e->stride * SrcStartIndex;
4295 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4296 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4298 context_release(context);
4300 return hr;
4303 /*****
4304 * Get / Set Texture Stage States
4305 * TODO: Verify against dx9 definitions
4306 *****/
4307 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4311 DWORD oldValue;
4313 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4315 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4317 WARN("Invalid Type %d passed.\n", Type);
4318 return WINED3D_OK;
4321 if (Stage >= gl_info->limits.texture_stages)
4323 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4324 Stage, gl_info->limits.texture_stages - 1);
4325 return WINED3D_OK;
4328 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4329 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4330 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4332 if (This->isRecordingState) {
4333 TRACE("Recording... not performing anything\n");
4334 return WINED3D_OK;
4337 /* Checked after the assignments to allow proper stateblock recording */
4338 if(oldValue == Value) {
4339 TRACE("App is setting the old value over, nothing to do\n");
4340 return WINED3D_OK;
4343 if (Stage > This->stateBlock->state.lowest_disabled_stage
4344 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4345 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4347 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4348 * Changes in other states are important on disabled stages too
4350 return WINED3D_OK;
4353 if(Type == WINED3DTSS_COLOROP) {
4354 unsigned int i;
4356 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4357 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4358 * they have to be disabled
4360 * The current stage is dirtified below.
4362 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4364 TRACE("Additionally dirtifying stage %u\n", i);
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4367 This->stateBlock->state.lowest_disabled_stage = Stage;
4368 TRACE("New lowest disabled: %u\n", Stage);
4369 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4370 /* Previously disabled stage enabled. Stages above it may need enabling
4371 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4372 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4374 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4377 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4379 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4380 break;
4381 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4384 This->stateBlock->state.lowest_disabled_stage = i;
4385 TRACE("New lowest disabled: %u\n", i);
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4391 return WINED3D_OK;
4394 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4398 TRACE("iface %p, stage %u, state %s, value %p.\n",
4399 iface, Stage, debug_d3dtexturestate(Type), pValue);
4401 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4403 WARN("Invalid Type %d passed.\n", Type);
4404 return WINED3D_OK;
4407 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4408 TRACE("Returning %#x.\n", *pValue);
4410 return WINED3D_OK;
4413 /*****
4414 * Get / Set Texture
4415 *****/
4416 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4417 DWORD stage, IWineD3DBaseTexture *texture)
4419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4420 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4421 IWineD3DBaseTexture *prev;
4423 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4425 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4426 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4428 /* Windows accepts overflowing this array... we do not. */
4429 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4431 WARN("Ignoring invalid stage %u.\n", stage);
4432 return WINED3D_OK;
4435 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4436 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4438 WARN("Rejecting attempt to set scratch texture.\n");
4439 return WINED3DERR_INVALIDCALL;
4442 This->updateStateBlock->changed.textures |= 1 << stage;
4444 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4445 TRACE("Previous texture %p.\n", prev);
4447 if (texture == prev)
4449 TRACE("App is setting the same texture again, nothing to do.\n");
4450 return WINED3D_OK;
4453 TRACE("Setting new texture to %p.\n", texture);
4454 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4456 if (This->isRecordingState)
4458 TRACE("Recording... not performing anything\n");
4460 if (texture) IWineD3DBaseTexture_AddRef(texture);
4461 if (prev) IWineD3DBaseTexture_Release(prev);
4463 return WINED3D_OK;
4466 if (texture)
4468 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4469 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4470 GLenum dimensions = t->baseTexture.target;
4472 IWineD3DBaseTexture_AddRef(texture);
4474 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4477 if (!prev && stage < gl_info->limits.texture_stages)
4479 /* The source arguments for color and alpha ops have different
4480 * meanings when a NULL texture is bound, so the COLOROP and
4481 * ALPHAOP have to be dirtified. */
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4486 if (bind_count == 1) t->baseTexture.sampler = stage;
4489 if (prev)
4491 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4492 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4494 IWineD3DBaseTexture_Release(prev);
4496 if (!texture && stage < gl_info->limits.texture_stages)
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4502 if (bind_count && t->baseTexture.sampler == stage)
4504 unsigned int i;
4506 /* Search for other stages the texture is bound to. Shouldn't
4507 * happen if applications bind textures to a single stage only. */
4508 TRACE("Searching for other stages the texture is bound to.\n");
4509 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4511 if (This->updateStateBlock->state.textures[i] == t)
4513 TRACE("Texture is also bound to stage %u.\n", i);
4514 t->baseTexture.sampler = i;
4515 break;
4521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4523 return WINED3D_OK;
4526 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4531 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4532 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4535 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4537 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4538 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4541 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4542 if (*ppTexture)
4543 IWineD3DBaseTexture_AddRef(*ppTexture);
4545 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4547 return WINED3D_OK;
4550 /*****
4551 * Get Back Buffer
4552 *****/
4553 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4554 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4556 IWineD3DSwapChain *swapchain;
4557 HRESULT hr;
4559 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4560 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4562 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4563 if (FAILED(hr))
4565 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4566 return hr;
4569 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4570 IWineD3DSwapChain_Release(swapchain);
4571 if (FAILED(hr))
4573 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4574 return hr;
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 WARN("(%p) : stub, calling idirect3d for now\n", This);
4583 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4586 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 IWineD3DSwapChain *swapChain;
4589 HRESULT hr;
4591 if(iSwapChain > 0) {
4592 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4593 if (hr == WINED3D_OK) {
4594 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4595 IWineD3DSwapChain_Release(swapChain);
4596 } else {
4597 FIXME("(%p) Error getting display mode\n", This);
4599 } else {
4600 /* Don't read the real display mode,
4601 but return the stored mode instead. X11 can't change the color
4602 depth, and some apps are pretty angry if they SetDisplayMode from
4603 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4605 Also don't relay to the swapchain because with ddraw it's possible
4606 that there isn't a swapchain at all */
4607 pMode->Width = This->ddraw_width;
4608 pMode->Height = This->ddraw_height;
4609 pMode->Format = This->ddraw_format;
4610 pMode->RefreshRate = 0;
4611 hr = WINED3D_OK;
4614 return hr;
4617 /*****
4618 * Stateblock related functions
4619 *****/
4621 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 IWineD3DStateBlock *stateblock;
4624 HRESULT hr;
4626 TRACE("(%p)\n", This);
4628 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4630 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4631 if (FAILED(hr)) return hr;
4633 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4634 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4635 This->isRecordingState = TRUE;
4637 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4639 return WINED3D_OK;
4642 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4646 if (!This->isRecordingState) {
4647 WARN("(%p) not recording! returning error\n", This);
4648 *ppStateBlock = NULL;
4649 return WINED3DERR_INVALIDCALL;
4652 stateblock_init_contained_states(object);
4654 *ppStateBlock = (IWineD3DStateBlock*) object;
4655 This->isRecordingState = FALSE;
4656 This->updateStateBlock = This->stateBlock;
4657 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4658 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4660 return WINED3D_OK;
4663 /*****
4664 * Scene related functions
4665 *****/
4666 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4667 /* At the moment we have no need for any functionality at the beginning
4668 of a scene */
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 TRACE("(%p)\n", This);
4672 if(This->inScene) {
4673 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4674 return WINED3DERR_INVALIDCALL;
4676 This->inScene = TRUE;
4677 return WINED3D_OK;
4680 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 struct wined3d_context *context;
4685 TRACE("(%p)\n", This);
4687 if(!This->inScene) {
4688 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4689 return WINED3DERR_INVALIDCALL;
4692 context = context_acquire(This, NULL);
4693 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4694 wglFlush();
4695 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4696 * fails. */
4697 context_release(context);
4699 This->inScene = FALSE;
4700 return WINED3D_OK;
4703 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4704 const RECT *pSourceRect, const RECT *pDestRect,
4705 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4707 IWineD3DSwapChain *swapChain = NULL;
4708 int i;
4709 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4711 TRACE("iface %p.\n", iface);
4713 for(i = 0 ; i < swapchains ; i ++) {
4715 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4716 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4717 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4718 IWineD3DSwapChain_Release(swapChain);
4721 return WINED3D_OK;
4724 /* Do not call while under the GL lock. */
4725 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4726 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4728 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4729 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4730 RECT draw_rect;
4732 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4733 iface, rect_count, rects, flags, color, depth, stencil);
4735 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4737 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4738 /* TODO: What about depth stencil buffers without stencil bits? */
4739 return WINED3DERR_INVALIDCALL;
4742 device_get_draw_rect(device, &draw_rect);
4744 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4745 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4748 /*****
4749 * Drawing functions
4750 *****/
4752 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4753 WINED3DPRIMITIVETYPE primitive_type)
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4759 This->updateStateBlock->changed.primitive_type = TRUE;
4760 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4763 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4764 WINED3DPRIMITIVETYPE *primitive_type)
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4770 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4772 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4775 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4781 if (!This->stateBlock->state.vertex_declaration)
4783 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4784 return WINED3DERR_INVALIDCALL;
4787 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4788 if (This->stateBlock->state.user_stream)
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4791 This->stateBlock->state.user_stream = FALSE;
4794 if (This->stateBlock->state.load_base_vertex_index)
4796 This->stateBlock->state.load_base_vertex_index = 0;
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4799 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4800 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 struct wined3d_buffer *index_buffer;
4808 UINT idxStride = 2;
4809 GLuint vbo;
4811 index_buffer = This->stateBlock->state.index_buffer;
4812 if (!index_buffer)
4814 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4815 * without an index buffer set. (The first time at least...)
4816 * D3D8 simply dies, but I doubt it can do much harm to return
4817 * D3DERR_INVALIDCALL there as well. */
4818 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4819 return WINED3DERR_INVALIDCALL;
4822 if (!This->stateBlock->state.vertex_declaration)
4824 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4825 return WINED3DERR_INVALIDCALL;
4828 if (This->stateBlock->state.user_stream)
4830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4831 This->stateBlock->state.user_stream = FALSE;
4833 vbo = index_buffer->buffer_object;
4835 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4837 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4838 idxStride = 2;
4839 else
4840 idxStride = 4;
4842 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4844 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4848 drawPrimitive(This, index_count, startIndex, idxStride,
4849 vbo ? NULL : index_buffer->resource.allocatedMemory);
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4855 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4858 struct wined3d_stream_state *stream;
4859 IWineD3DBuffer *vb;
4861 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4862 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4864 if (!This->stateBlock->state.vertex_declaration)
4866 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4867 return WINED3DERR_INVALIDCALL;
4870 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4871 stream = &This->stateBlock->state.streams[0];
4872 vb = (IWineD3DBuffer *)stream->buffer;
4873 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4874 if (vb) IWineD3DBuffer_Release(vb);
4875 stream->offset = 0;
4876 stream->stride = VertexStreamZeroStride;
4877 This->stateBlock->state.user_stream = TRUE;
4878 This->stateBlock->state.load_base_vertex_index = 0;
4880 /* TODO: Only mark dirty if drawing from a different UP address */
4881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4883 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4885 /* MSDN specifies stream zero settings must be set to NULL */
4886 stream->buffer = NULL;
4887 stream->stride = 0;
4889 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4890 * the new stream sources or use UP drawing again
4892 return WINED3D_OK;
4895 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4896 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4897 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4899 int idxStride;
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 struct wined3d_stream_state *stream;
4902 IWineD3DBuffer *vb;
4903 IWineD3DBuffer *ib;
4905 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4906 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4908 if (!This->stateBlock->state.vertex_declaration)
4910 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4911 return WINED3DERR_INVALIDCALL;
4914 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4915 idxStride = 2;
4916 } else {
4917 idxStride = 4;
4920 stream = &This->stateBlock->state.streams[0];
4921 vb = (IWineD3DBuffer *)stream->buffer;
4922 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4923 if (vb) IWineD3DBuffer_Release(vb);
4924 stream->offset = 0;
4925 stream->stride = VertexStreamZeroStride;
4926 This->stateBlock->state.user_stream = TRUE;
4928 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4929 This->stateBlock->state.base_vertex_index = 0;
4930 This->stateBlock->state.load_base_vertex_index = 0;
4931 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4935 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4937 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4938 stream->buffer = NULL;
4939 stream->stride = 0;
4940 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4941 if (ib)
4943 IWineD3DBuffer_Release(ib);
4944 This->stateBlock->state.index_buffer = NULL;
4946 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4947 * SetStreamSource to specify a vertex buffer
4950 return WINED3D_OK;
4953 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4954 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4958 /* Mark the state dirty until we have nicer tracking
4959 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4960 * that value.
4962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4964 This->stateBlock->state.base_vertex_index = 0;
4965 This->up_strided = DrawPrimStrideData;
4966 drawPrimitive(This, vertex_count, 0, 0, NULL);
4967 This->up_strided = NULL;
4968 return WINED3D_OK;
4971 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4972 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4973 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4976 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4978 /* Mark the state dirty until we have nicer tracking
4979 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4980 * that value.
4982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4983 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4984 This->stateBlock->state.user_stream = TRUE;
4985 This->stateBlock->state.base_vertex_index = 0;
4986 This->up_strided = DrawPrimStrideData;
4987 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4988 This->up_strided = NULL;
4989 return WINED3D_OK;
4992 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4993 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4994 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4996 WINED3DLOCKED_BOX src;
4997 WINED3DLOCKED_BOX dst;
4998 HRESULT hr;
5000 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5001 iface, pSourceVolume, pDestinationVolume);
5003 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5004 * dirtification to improve loading performance.
5006 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5007 if (FAILED(hr)) return hr;
5008 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5009 if (FAILED(hr))
5011 IWineD3DVolume_Unmap(pSourceVolume);
5012 return hr;
5015 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5017 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5018 if (FAILED(hr))
5019 IWineD3DVolume_Unmap(pSourceVolume);
5020 else
5021 hr = IWineD3DVolume_Unmap(pSourceVolume);
5023 return hr;
5026 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5027 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5029 unsigned int level_count, i;
5030 WINED3DRESOURCETYPE type;
5031 HRESULT hr;
5033 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5035 /* Verify that the source and destination textures are non-NULL. */
5036 if (!src_texture || !dst_texture)
5038 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5039 return WINED3DERR_INVALIDCALL;
5042 if (src_texture == dst_texture)
5044 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5045 return WINED3DERR_INVALIDCALL;
5048 /* Verify that the source and destination textures are the same type. */
5049 type = IWineD3DBaseTexture_GetType(src_texture);
5050 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5052 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5053 return WINED3DERR_INVALIDCALL;
5056 /* Check that both textures have the identical numbers of levels. */
5057 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5058 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5060 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5061 return WINED3DERR_INVALIDCALL;
5064 /* Make sure that the destination texture is loaded. */
5065 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.texture_ops->texture_preload(
5066 (IWineD3DBaseTextureImpl *)dst_texture, SRGB_RGB);
5068 /* Update every surface level of the texture. */
5069 switch (type)
5071 case WINED3DRTYPE_TEXTURE:
5073 IWineD3DSurface *src_surface;
5074 IWineD3DSurface *dst_surface;
5076 for (i = 0; i < level_count; ++i)
5078 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5079 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5080 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5081 IWineD3DSurface_Release(dst_surface);
5082 IWineD3DSurface_Release(src_surface);
5083 if (FAILED(hr))
5085 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5086 return hr;
5089 break;
5092 case WINED3DRTYPE_CUBETEXTURE:
5094 IWineD3DSurface *src_surface;
5095 IWineD3DSurface *dst_surface;
5097 for (i = 0; i < level_count * 6; ++i)
5099 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5100 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5101 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5102 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5103 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5104 IWineD3DSurface_Release(dst_surface);
5105 IWineD3DSurface_Release(src_surface);
5106 if (FAILED(hr))
5108 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5109 return hr;
5112 break;
5115 case WINED3DRTYPE_VOLUMETEXTURE:
5117 IWineD3DVolume *src_volume;
5118 IWineD3DVolume *dst_volume;
5120 for (i = 0; i < level_count; ++i)
5122 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5123 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5124 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5125 IWineD3DVolume_Release(dst_volume);
5126 IWineD3DVolume_Release(src_volume);
5127 if (FAILED(hr))
5129 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5130 return hr;
5133 break;
5136 default:
5137 FIXME("Unsupported texture type %#x.\n", type);
5138 return WINED3DERR_INVALIDCALL;
5141 return WINED3D_OK;
5144 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5145 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5147 IWineD3DSwapChain *swapchain;
5148 HRESULT hr;
5150 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5152 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5153 if (FAILED(hr)) return hr;
5155 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5156 IWineD3DSwapChain_Release(swapchain);
5158 return hr;
5161 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 IWineD3DBaseTextureImpl *texture;
5164 DWORD i;
5166 TRACE("(%p) : %p\n", This, pNumPasses);
5168 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5170 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5172 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5173 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5175 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5177 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5178 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5181 texture = This->stateBlock->state.textures[i];
5182 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5184 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5186 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5187 return E_FAIL;
5189 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5191 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5192 return E_FAIL;
5194 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5195 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5197 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5198 return E_FAIL;
5202 /* return a sensible default */
5203 *pNumPasses = 1;
5205 TRACE("returning D3D_OK\n");
5206 return WINED3D_OK;
5209 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5211 int i;
5213 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5215 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5216 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5217 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5219 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5224 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5226 int j;
5227 UINT NewSize;
5228 PALETTEENTRY **palettes;
5230 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5232 if (PaletteNumber >= MAX_PALETTES) {
5233 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5234 return WINED3DERR_INVALIDCALL;
5237 if (PaletteNumber >= This->NumberOfPalettes) {
5238 NewSize = This->NumberOfPalettes;
5239 do {
5240 NewSize *= 2;
5241 } while(PaletteNumber >= NewSize);
5242 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5243 if (!palettes) {
5244 ERR("Out of memory!\n");
5245 return E_OUTOFMEMORY;
5247 This->palettes = palettes;
5248 This->NumberOfPalettes = NewSize;
5251 if (!This->palettes[PaletteNumber]) {
5252 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5253 if (!This->palettes[PaletteNumber]) {
5254 ERR("Out of memory!\n");
5255 return E_OUTOFMEMORY;
5259 for (j = 0; j < 256; ++j) {
5260 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5261 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5262 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5263 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5265 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5266 TRACE("(%p) : returning\n", This);
5267 return WINED3D_OK;
5270 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 int j;
5273 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5274 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5275 /* What happens in such situation isn't documented; Native seems to silently abort
5276 on such conditions. Return Invalid Call. */
5277 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5278 return WINED3DERR_INVALIDCALL;
5280 for (j = 0; j < 256; ++j) {
5281 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5282 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5283 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5284 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5286 TRACE("(%p) : returning\n", This);
5287 return WINED3D_OK;
5290 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5292 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5293 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5294 (tested with reference rasterizer). Return Invalid Call. */
5295 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5296 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5297 return WINED3DERR_INVALIDCALL;
5299 /*TODO: stateblocks */
5300 if (This->currentPalette != PaletteNumber) {
5301 This->currentPalette = PaletteNumber;
5302 dirtify_p8_texture_samplers(This);
5304 TRACE("(%p) : returning\n", This);
5305 return WINED3D_OK;
5308 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5311 if (!PaletteNumber)
5313 WARN("(%p) : returning Invalid Call\n", This);
5314 return WINED3DERR_INVALIDCALL;
5316 /*TODO: stateblocks */
5317 *PaletteNumber = This->currentPalette;
5318 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5319 return WINED3D_OK;
5322 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5324 static BOOL warned;
5325 if (!warned)
5327 FIXME("(%p) : stub\n", This);
5328 warned = TRUE;
5331 This->softwareVertexProcessing = bSoftware;
5332 return WINED3D_OK;
5336 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 static BOOL warned;
5339 if (!warned)
5341 FIXME("(%p) : stub\n", This);
5342 warned = TRUE;
5344 return This->softwareVertexProcessing;
5347 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5348 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5350 IWineD3DSwapChain *swapchain;
5351 HRESULT hr;
5353 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5354 iface, swapchain_idx, raster_status);
5356 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5357 if (FAILED(hr))
5359 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5360 return hr;
5363 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5364 IWineD3DSwapChain_Release(swapchain);
5365 if (FAILED(hr))
5367 WARN("Failed to get raster status, hr %#x.\n", hr);
5368 return hr;
5371 return WINED3D_OK;
5374 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5376 static BOOL warned;
5377 if(nSegments != 0.0f) {
5378 if (!warned)
5380 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5381 warned = TRUE;
5384 return WINED3D_OK;
5387 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5389 static BOOL warned;
5390 if (!warned)
5392 FIXME("iface %p stub!\n", iface);
5393 warned = TRUE;
5395 return 0.0f;
5398 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5399 IWineD3DSurface *src_surface, const RECT *src_rect,
5400 IWineD3DSurface *dst_surface, const POINT *dst_point)
5402 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5403 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5405 const struct wined3d_format *src_format;
5406 const struct wined3d_format *dst_format;
5407 const struct wined3d_gl_info *gl_info;
5408 struct wined3d_context *context;
5409 const unsigned char *data;
5410 UINT update_w, update_h;
5411 CONVERT_TYPES convert;
5412 UINT src_w, src_h;
5413 UINT dst_x, dst_y;
5414 DWORD sampler;
5415 struct wined3d_format format;
5417 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5418 iface, src_surface, wine_dbgstr_rect(src_rect),
5419 dst_surface, wine_dbgstr_point(dst_point));
5421 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5423 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5424 src_surface, dst_surface);
5425 return WINED3DERR_INVALIDCALL;
5428 src_format = src_impl->resource.format;
5429 dst_format = dst_impl->resource.format;
5431 if (src_format->id != dst_format->id)
5433 WARN("Source and destination surfaces should have the same format.\n");
5434 return WINED3DERR_INVALIDCALL;
5437 dst_x = dst_point ? dst_point->x : 0;
5438 dst_y = dst_point ? dst_point->y : 0;
5440 /* This call loads the OpenGL surface directly, instead of copying the
5441 * surface to the destination's sysmem copy. If surface conversion is
5442 * needed, use BltFast instead to copy in sysmem and use regular surface
5443 * loading. */
5444 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5445 if (convert != NO_CONVERSION || format.convert)
5446 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5448 context = context_acquire(This, NULL);
5449 gl_info = context->gl_info;
5451 ENTER_GL();
5452 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5453 checkGLcall("glActiveTextureARB");
5454 LEAVE_GL();
5456 /* Make sure the surface is loaded and up to date */
5457 surface_internal_preload(dst_impl, SRGB_RGB);
5458 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5460 src_w = src_impl->currentDesc.Width;
5461 src_h = src_impl->currentDesc.Height;
5462 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5463 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5465 data = IWineD3DSurface_GetData(src_surface);
5466 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5468 ENTER_GL();
5470 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5472 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5473 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5474 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5476 if (src_rect)
5478 data += (src_rect->top / src_format->block_height) * src_pitch;
5479 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5482 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5483 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5484 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5486 if (row_length == src_pitch)
5488 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5489 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5491 else
5493 UINT row, y;
5495 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5496 * can't use the unpack row length like below. */
5497 for (row = 0, y = dst_y; row < row_count; ++row)
5499 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5500 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5501 y += src_format->block_height;
5502 data += src_pitch;
5505 checkGLcall("glCompressedTexSubImage2DARB");
5507 else
5509 if (src_rect)
5511 data += src_rect->top * src_w * src_format->byte_count;
5512 data += src_rect->left * src_format->byte_count;
5515 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5516 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5517 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5519 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5520 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5521 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5522 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5523 checkGLcall("glTexSubImage2D");
5526 LEAVE_GL();
5527 context_release(context);
5529 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5530 sampler = This->rev_tex_unit_map[0];
5531 if (sampler != WINED3D_UNMAPPED_STAGE)
5533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5536 return WINED3D_OK;
5539 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5541 struct WineD3DRectPatch *patch;
5542 GLenum old_primitive_type;
5543 unsigned int i;
5544 struct list *e;
5545 BOOL found;
5546 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5548 if(!(Handle || pRectPatchInfo)) {
5549 /* TODO: Write a test for the return value, thus the FIXME */
5550 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5551 return WINED3DERR_INVALIDCALL;
5554 if(Handle) {
5555 i = PATCHMAP_HASHFUNC(Handle);
5556 found = FALSE;
5557 LIST_FOR_EACH(e, &This->patches[i]) {
5558 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5559 if(patch->Handle == Handle) {
5560 found = TRUE;
5561 break;
5565 if(!found) {
5566 TRACE("Patch does not exist. Creating a new one\n");
5567 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5568 patch->Handle = Handle;
5569 list_add_head(&This->patches[i], &patch->entry);
5570 } else {
5571 TRACE("Found existing patch %p\n", patch);
5573 } else {
5574 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5575 * attributes we have to tesselate, read back, and draw. This needs a patch
5576 * management structure instance. Create one.
5578 * A possible improvement is to check if a vertex shader is used, and if not directly
5579 * draw the patch.
5581 FIXME("Drawing an uncached patch. This is slow\n");
5582 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5585 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5586 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5587 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5589 HRESULT hr;
5590 TRACE("Tesselation density or patch info changed, retesselating\n");
5592 if(pRectPatchInfo) {
5593 patch->RectPatchInfo = *pRectPatchInfo;
5595 patch->numSegs[0] = pNumSegs[0];
5596 patch->numSegs[1] = pNumSegs[1];
5597 patch->numSegs[2] = pNumSegs[2];
5598 patch->numSegs[3] = pNumSegs[3];
5600 hr = tesselate_rectpatch(This, patch);
5601 if(FAILED(hr)) {
5602 WARN("Patch tesselation failed\n");
5604 /* Do not release the handle to store the params of the patch */
5605 if(!Handle) {
5606 HeapFree(GetProcessHeap(), 0, patch);
5608 return hr;
5612 This->currentPatch = patch;
5613 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5614 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5615 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5616 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5617 This->currentPatch = NULL;
5619 /* Destroy uncached patches */
5620 if(!Handle) {
5621 HeapFree(GetProcessHeap(), 0, patch->mem);
5622 HeapFree(GetProcessHeap(), 0, patch);
5624 return WINED3D_OK;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5628 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5630 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5631 iface, handle, segment_count, patch_info);
5633 return WINED3D_OK;
5636 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 int i;
5639 struct WineD3DRectPatch *patch;
5640 struct list *e;
5641 TRACE("(%p) Handle(%d)\n", This, Handle);
5643 i = PATCHMAP_HASHFUNC(Handle);
5644 LIST_FOR_EACH(e, &This->patches[i]) {
5645 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5646 if(patch->Handle == Handle) {
5647 TRACE("Deleting patch %p\n", patch);
5648 list_remove(&patch->entry);
5649 HeapFree(GetProcessHeap(), 0, patch->mem);
5650 HeapFree(GetProcessHeap(), 0, patch);
5651 return WINED3D_OK;
5655 /* TODO: Write a test for the return value */
5656 FIXME("Attempt to destroy nonexistent patch\n");
5657 return WINED3DERR_INVALIDCALL;
5660 /* Do not call while under the GL lock. */
5661 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5662 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5664 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5666 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5667 iface, surface, wine_dbgstr_rect(rect),
5668 color->r, color->g, color->b, color->a);
5670 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5672 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5673 return WINED3DERR_INVALIDCALL;
5676 return surface_color_fill(s, rect, color);
5679 /* Do not call while under the GL lock. */
5680 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5681 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5683 IWineD3DResource *resource;
5684 HRESULT hr;
5686 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5687 if (FAILED(hr))
5689 ERR("Failed to get resource, hr %#x\n", hr);
5690 return;
5693 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5695 FIXME("Only supported on surface resources\n");
5696 IWineD3DResource_Release(resource);
5697 return;
5700 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5701 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5703 IWineD3DResource_Release(resource);
5706 /* rendertarget and depth stencil functions */
5707 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5708 DWORD render_target_idx, IWineD3DSurface **render_target)
5710 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5712 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5713 iface, render_target_idx, render_target);
5715 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5717 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5718 return WINED3DERR_INVALIDCALL;
5721 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5722 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5724 TRACE("Returning render target %p.\n", *render_target);
5726 return WINED3D_OK;
5729 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5731 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5733 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5735 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5736 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5737 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5738 IWineD3DSurface_AddRef(*depth_stencil);
5740 return WINED3D_OK;
5743 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5744 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5746 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5747 IWineD3DSurfaceImpl *prev;
5749 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5750 iface, render_target_idx, render_target, set_viewport);
5752 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5754 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5755 return WINED3DERR_INVALIDCALL;
5758 prev = device->render_targets[render_target_idx];
5759 if (render_target == (IWineD3DSurface *)prev)
5761 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5762 return WINED3D_OK;
5765 /* Render target 0 can't be set to NULL. */
5766 if (!render_target && !render_target_idx)
5768 WARN("Trying to set render target 0 to NULL.\n");
5769 return WINED3DERR_INVALIDCALL;
5772 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5774 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5775 return WINED3DERR_INVALIDCALL;
5778 if (render_target) IWineD3DSurface_AddRef(render_target);
5779 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5780 /* Release after the assignment, to prevent device_resource_released()
5781 * from seeing the surface as still in use. */
5782 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5784 /* Render target 0 is special. */
5785 if (!render_target_idx && set_viewport)
5787 /* Set the viewport and scissor rectangles, if requested. Tests show
5788 * that stateblock recording is ignored, the change goes directly
5789 * into the primary stateblock. */
5790 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5791 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5792 device->stateBlock->state.viewport.X = 0;
5793 device->stateBlock->state.viewport.Y = 0;
5794 device->stateBlock->state.viewport.MaxZ = 1.0f;
5795 device->stateBlock->state.viewport.MinZ = 0.0f;
5796 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5798 device->stateBlock->state.scissor_rect.top = 0;
5799 device->stateBlock->state.scissor_rect.left = 0;
5800 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5801 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5802 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5805 return WINED3D_OK;
5808 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5811 IWineD3DSurfaceImpl *tmp;
5813 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5815 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5817 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5818 return WINED3D_OK;
5821 if (This->depth_stencil)
5823 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5824 || This->depth_stencil->flags & SFLAG_DISCARD)
5826 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5827 This->depth_stencil->currentDesc.Width,
5828 This->depth_stencil->currentDesc.Height);
5829 if (This->depth_stencil == This->onscreen_depth_stencil)
5831 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5832 This->onscreen_depth_stencil = NULL;
5837 tmp = This->depth_stencil;
5838 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5839 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5840 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5842 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5844 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5850 return WINED3D_OK;
5853 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5854 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5857 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5858 WINED3DLOCKED_RECT lockedRect;
5860 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5861 iface, XHotSpot, YHotSpot, cursor_image);
5863 /* some basic validation checks */
5864 if (This->cursorTexture)
5866 struct wined3d_context *context = context_acquire(This, NULL);
5867 ENTER_GL();
5868 glDeleteTextures(1, &This->cursorTexture);
5869 LEAVE_GL();
5870 context_release(context);
5871 This->cursorTexture = 0;
5874 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5875 This->haveHardwareCursor = TRUE;
5876 else
5877 This->haveHardwareCursor = FALSE;
5879 if (cursor_image)
5881 WINED3DLOCKED_RECT rect;
5883 /* MSDN: Cursor must be A8R8G8B8 */
5884 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5886 WARN("surface %p has an invalid format.\n", cursor_image);
5887 return WINED3DERR_INVALIDCALL;
5890 /* MSDN: Cursor must be smaller than the display mode */
5891 if (s->currentDesc.Width > This->ddraw_width
5892 || s->currentDesc.Height > This->ddraw_height)
5894 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5895 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5896 return WINED3DERR_INVALIDCALL;
5899 if (!This->haveHardwareCursor) {
5900 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5902 /* Do not store the surface's pointer because the application may
5903 * release it after setting the cursor image. Windows doesn't
5904 * addref the set surface, so we can't do this either without
5905 * creating circular refcount dependencies. Copy out the gl texture
5906 * instead.
5908 This->cursorWidth = s->currentDesc.Width;
5909 This->cursorHeight = s->currentDesc.Height;
5910 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5912 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5913 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5914 struct wined3d_context *context;
5915 char *mem, *bits = rect.pBits;
5916 GLint intfmt = format->glInternal;
5917 GLint gl_format = format->glFormat;
5918 GLint type = format->glType;
5919 INT height = This->cursorHeight;
5920 INT width = This->cursorWidth;
5921 INT bpp = format->byte_count;
5922 DWORD sampler;
5923 INT i;
5925 /* Reformat the texture memory (pitch and width can be
5926 * different) */
5927 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5928 for(i = 0; i < height; i++)
5929 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5930 IWineD3DSurface_Unmap(cursor_image);
5932 context = context_acquire(This, NULL);
5934 ENTER_GL();
5936 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5938 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5939 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5942 /* Make sure that a proper texture unit is selected */
5943 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5944 checkGLcall("glActiveTextureARB");
5945 sampler = This->rev_tex_unit_map[0];
5946 if (sampler != WINED3D_UNMAPPED_STAGE)
5948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5950 /* Create a new cursor texture */
5951 glGenTextures(1, &This->cursorTexture);
5952 checkGLcall("glGenTextures");
5953 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5954 checkGLcall("glBindTexture");
5955 /* Copy the bitmap memory into the cursor texture */
5956 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5957 checkGLcall("glTexImage2D");
5958 HeapFree(GetProcessHeap(), 0, mem);
5960 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5962 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5963 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5966 LEAVE_GL();
5968 context_release(context);
5970 else
5972 FIXME("A cursor texture was not returned.\n");
5973 This->cursorTexture = 0;
5976 else
5978 /* Draw a hardware cursor */
5979 ICONINFO cursorInfo;
5980 HCURSOR cursor;
5981 /* Create and clear maskBits because it is not needed for
5982 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5983 * chunks. */
5984 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5985 (s->currentDesc.Width * s->currentDesc.Height / 8));
5986 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5987 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5988 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5990 cursorInfo.fIcon = FALSE;
5991 cursorInfo.xHotspot = XHotSpot;
5992 cursorInfo.yHotspot = YHotSpot;
5993 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5994 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5995 IWineD3DSurface_Unmap(cursor_image);
5996 /* Create our cursor and clean up. */
5997 cursor = CreateIconIndirect(&cursorInfo);
5998 SetCursor(cursor);
5999 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6000 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6001 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6002 This->hardwareCursor = cursor;
6003 HeapFree(GetProcessHeap(), 0, maskBits);
6007 This->xHotSpot = XHotSpot;
6008 This->yHotSpot = YHotSpot;
6009 return WINED3D_OK;
6012 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6013 int XScreenSpace, int YScreenSpace, DWORD flags)
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6017 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6018 iface, XScreenSpace, YScreenSpace, flags);
6020 This->xScreenSpace = XScreenSpace;
6021 This->yScreenSpace = YScreenSpace;
6024 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6026 BOOL oldVisible = This->bCursorVisible;
6027 POINT pt;
6029 TRACE("(%p) : visible(%d)\n", This, bShow);
6032 * When ShowCursor is first called it should make the cursor appear at the OS's last
6033 * known cursor position. Because of this, some applications just repetitively call
6034 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6036 GetCursorPos(&pt);
6037 This->xScreenSpace = pt.x;
6038 This->yScreenSpace = pt.y;
6040 if (This->haveHardwareCursor) {
6041 This->bCursorVisible = bShow;
6042 if (bShow)
6043 SetCursor(This->hardwareCursor);
6044 else
6045 SetCursor(NULL);
6047 else
6049 if (This->cursorTexture)
6050 This->bCursorVisible = bShow;
6053 return oldVisible;
6056 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6057 TRACE("checking resource %p for eviction\n", resource);
6058 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6059 TRACE("Evicting %p\n", resource);
6060 IWineD3DResource_UnLoad(resource);
6062 IWineD3DResource_Release(resource);
6063 return S_OK;
6066 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6068 TRACE("iface %p.\n", iface);
6070 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6071 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6072 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6074 return WINED3D_OK;
6077 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6079 IWineD3DDeviceImpl *device = surface->resource.device;
6080 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6082 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6083 if (surface->flags & SFLAG_DIBSECTION)
6085 /* Release the DC */
6086 SelectObject(surface->hDC, surface->dib.holdbitmap);
6087 DeleteDC(surface->hDC);
6088 /* Release the DIB section */
6089 DeleteObject(surface->dib.DIBsection);
6090 surface->dib.bitmap_data = NULL;
6091 surface->resource.allocatedMemory = NULL;
6092 surface->flags &= ~SFLAG_DIBSECTION;
6094 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6095 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6096 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6097 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6099 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6100 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6101 } else {
6102 surface->pow2Width = surface->pow2Height = 1;
6103 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6104 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6107 if (surface->texture_name)
6109 struct wined3d_context *context = context_acquire(device, NULL);
6110 ENTER_GL();
6111 glDeleteTextures(1, &surface->texture_name);
6112 LEAVE_GL();
6113 context_release(context);
6114 surface->texture_name = 0;
6115 surface->flags &= ~SFLAG_CLIENT;
6117 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6118 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6120 surface->flags |= SFLAG_NONPOW2;
6122 else
6124 surface->flags &= ~SFLAG_NONPOW2;
6126 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6127 surface->resource.allocatedMemory = NULL;
6128 surface->resource.heapMemory = NULL;
6129 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6131 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6132 * to a FBO */
6133 if (!surface_init_sysmem(surface))
6135 return E_OUTOFMEMORY;
6137 return WINED3D_OK;
6140 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6141 TRACE("Unloading resource %p\n", resource);
6142 IWineD3DResource_UnLoad(resource);
6143 IWineD3DResource_Release(resource);
6144 return S_OK;
6147 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6149 UINT i, count;
6150 WINED3DDISPLAYMODE m;
6151 HRESULT hr;
6153 /* All Windowed modes are supported, as is leaving the current mode */
6154 if(pp->Windowed) return TRUE;
6155 if(!pp->BackBufferWidth) return TRUE;
6156 if(!pp->BackBufferHeight) return TRUE;
6158 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6159 for(i = 0; i < count; i++) {
6160 memset(&m, 0, sizeof(m));
6161 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6162 if(FAILED(hr)) {
6163 ERR("EnumAdapterModes failed\n");
6165 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6166 /* Mode found, it is supported */
6167 return TRUE;
6170 /* Mode not found -> not supported */
6171 return FALSE;
6174 /* Do not call while under the GL lock. */
6175 static void delete_opengl_contexts(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6177 const struct wined3d_gl_info *gl_info;
6178 struct wined3d_context *context;
6179 IWineD3DBaseShaderImpl *shader;
6181 context = context_acquire(device, NULL);
6182 gl_info = context->gl_info;
6184 IWineD3DDevice_EnumResources((IWineD3DDevice *)device, reset_unload_resources, NULL);
6185 LIST_FOR_EACH_ENTRY(shader, &device->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry)
6187 device->shader_backend->shader_destroy(shader);
6190 ENTER_GL();
6191 if (device->depth_blt_texture)
6193 glDeleteTextures(1, &device->depth_blt_texture);
6194 device->depth_blt_texture = 0;
6196 if (device->depth_blt_rb)
6198 gl_info->fbo_ops.glDeleteRenderbuffers(1, &device->depth_blt_rb);
6199 device->depth_blt_rb = 0;
6200 device->depth_blt_rb_w = 0;
6201 device->depth_blt_rb_h = 0;
6203 LEAVE_GL();
6205 device->blitter->free_private(device);
6206 device->frag_pipe->free_private(device);
6207 device->shader_backend->shader_free_private(device);
6208 destroy_dummy_textures(device, gl_info);
6210 context_release(context);
6212 while (device->numContexts)
6214 context_destroy(device, device->contexts[0]);
6216 HeapFree(GetProcessHeap(), 0, swapchain->context);
6217 swapchain->context = NULL;
6218 swapchain->num_contexts = 0;
6221 /* Do not call while under the GL lock. */
6222 static HRESULT create_primary_opengl_context(IWineD3DDeviceImpl *device, IWineD3DSwapChainImpl *swapchain)
6224 struct wined3d_context *context;
6225 HRESULT hr;
6226 IWineD3DSurfaceImpl *target;
6228 /* Recreate the primary swapchain's context */
6229 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6230 if (!swapchain->context)
6232 ERR("Failed to allocate memory for swapchain context array.\n");
6233 return E_OUTOFMEMORY;
6236 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6237 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6239 WARN("Failed to create context.\n");
6240 HeapFree(GetProcessHeap(), 0, swapchain->context);
6241 return E_FAIL;
6244 swapchain->context[0] = context;
6245 swapchain->num_contexts = 1;
6246 create_dummy_textures(device);
6247 context_release(context);
6249 hr = device->shader_backend->shader_alloc_private(device);
6250 if (FAILED(hr))
6252 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6253 goto err;
6256 hr = device->frag_pipe->alloc_private(device);
6257 if (FAILED(hr))
6259 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6260 device->shader_backend->shader_free_private(device);
6261 goto err;
6264 hr = device->blitter->alloc_private(device);
6265 if (FAILED(hr))
6267 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6268 device->frag_pipe->free_private(device);
6269 device->shader_backend->shader_free_private(device);
6270 goto err;
6273 return WINED3D_OK;
6275 err:
6276 context_acquire(device, NULL);
6277 destroy_dummy_textures(device, context->gl_info);
6278 context_release(context);
6279 context_destroy(device, context);
6280 HeapFree(GetProcessHeap(), 0, swapchain->context);
6281 swapchain->num_contexts = 0;
6282 return hr;
6285 /* Do not call while under the GL lock. */
6286 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6287 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6290 IWineD3DSwapChainImpl *swapchain;
6291 HRESULT hr;
6292 BOOL DisplayModeChanged = FALSE;
6293 WINED3DDISPLAYMODE mode;
6294 TRACE("(%p)\n", This);
6296 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6297 if(FAILED(hr)) {
6298 ERR("Failed to get the first implicit swapchain\n");
6299 return hr;
6302 if(!is_display_mode_supported(This, pPresentationParameters)) {
6303 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6304 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6305 pPresentationParameters->BackBufferHeight);
6306 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6307 return WINED3DERR_INVALIDCALL;
6310 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6311 * on an existing gl context, so there's no real need for recreation.
6313 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6315 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6317 TRACE("New params:\n");
6318 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6319 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6320 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6321 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6322 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6323 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6324 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6325 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6326 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6327 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6328 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6329 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6330 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6332 /* No special treatment of these parameters. Just store them */
6333 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6334 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6335 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6336 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6338 /* What to do about these? */
6339 if (pPresentationParameters->BackBufferCount
6340 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6341 ERR("Cannot change the back buffer count yet\n");
6343 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6344 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6345 ERR("Cannot change the back buffer format yet\n");
6348 if (pPresentationParameters->hDeviceWindow
6349 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6350 ERR("Cannot change the device window yet\n");
6352 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6354 HRESULT hrc;
6356 TRACE("Creating the depth stencil buffer\n");
6358 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6359 pPresentationParameters->BackBufferWidth,
6360 pPresentationParameters->BackBufferHeight,
6361 pPresentationParameters->AutoDepthStencilFormat,
6362 pPresentationParameters->MultiSampleType,
6363 pPresentationParameters->MultiSampleQuality,
6364 FALSE,
6365 (IWineD3DSurface **)&This->auto_depth_stencil);
6367 if (FAILED(hrc)) {
6368 ERR("Failed to create the depth stencil buffer\n");
6369 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6370 return WINED3DERR_INVALIDCALL;
6374 if (This->onscreen_depth_stencil)
6376 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6377 This->onscreen_depth_stencil = NULL;
6380 /* Reset the depth stencil */
6381 if (pPresentationParameters->EnableAutoDepthStencil)
6382 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6383 else
6384 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6386 TRACE("Resetting stateblock\n");
6387 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6388 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6390 delete_opengl_contexts(This, swapchain);
6392 if(pPresentationParameters->Windowed) {
6393 mode.Width = swapchain->orig_width;
6394 mode.Height = swapchain->orig_height;
6395 mode.RefreshRate = 0;
6396 mode.Format = swapchain->presentParms.BackBufferFormat;
6397 } else {
6398 mode.Width = pPresentationParameters->BackBufferWidth;
6399 mode.Height = pPresentationParameters->BackBufferHeight;
6400 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6401 mode.Format = swapchain->presentParms.BackBufferFormat;
6404 /* Should Width == 800 && Height == 0 set 800x600? */
6405 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6406 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6407 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6409 UINT i;
6411 if(!pPresentationParameters->Windowed) {
6412 DisplayModeChanged = TRUE;
6414 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6415 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6417 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6418 if(FAILED(hr))
6420 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6421 return hr;
6424 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6426 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6427 if(FAILED(hr))
6429 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6430 return hr;
6433 if (This->auto_depth_stencil)
6435 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6436 if(FAILED(hr))
6438 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6439 return hr;
6444 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6445 || DisplayModeChanged)
6447 BOOL filter = This->filter_messages;
6448 This->filter_messages = TRUE;
6450 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6452 if (!pPresentationParameters->Windowed)
6454 if (swapchain->presentParms.Windowed)
6456 HWND focus_window = This->createParms.hFocusWindow;
6457 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6458 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6460 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6461 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6462 return hr;
6465 /* switch from windowed to fs */
6466 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6467 pPresentationParameters->BackBufferWidth,
6468 pPresentationParameters->BackBufferHeight);
6470 else
6472 /* Fullscreen -> fullscreen mode change */
6473 MoveWindow(swapchain->device_window, 0, 0,
6474 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6475 TRUE);
6478 else if (!swapchain->presentParms.Windowed)
6480 /* Fullscreen -> windowed switch */
6481 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6482 IWineD3DDevice_ReleaseFocusWindow(iface);
6484 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6486 This->filter_messages = filter;
6488 else if (!pPresentationParameters->Windowed)
6490 DWORD style = This->style, exStyle = This->exStyle;
6491 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6492 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6493 * Reset to clear up their mess. Guild Wars also loses the device during that.
6495 This->style = 0;
6496 This->exStyle = 0;
6497 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6498 pPresentationParameters->BackBufferWidth,
6499 pPresentationParameters->BackBufferHeight);
6500 This->style = style;
6501 This->exStyle = exStyle;
6504 /* Note: No parent needed for initial internal stateblock */
6505 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6506 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6507 else TRACE("Created stateblock %p\n", This->stateBlock);
6508 This->updateStateBlock = This->stateBlock;
6509 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6511 stateblock_init_default_state(This->stateBlock);
6513 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6515 RECT client_rect;
6516 GetClientRect(swapchain->win_handle, &client_rect);
6518 if(!swapchain->presentParms.BackBufferCount)
6520 TRACE("Single buffered rendering\n");
6521 swapchain->render_to_fbo = FALSE;
6523 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6524 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6526 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6527 swapchain->presentParms.BackBufferWidth,
6528 swapchain->presentParms.BackBufferHeight,
6529 client_rect.right, client_rect.bottom);
6530 swapchain->render_to_fbo = TRUE;
6532 else
6534 TRACE("Rendering directly to GL_BACK\n");
6535 swapchain->render_to_fbo = FALSE;
6539 hr = create_primary_opengl_context(This, swapchain);
6540 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6542 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6543 * first use
6545 return hr;
6548 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6550 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6552 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6554 return WINED3D_OK;
6558 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6560 TRACE("(%p) : pParameters %p\n", This, pParameters);
6562 *pParameters = This->createParms;
6563 return WINED3D_OK;
6566 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6567 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6569 IWineD3DSwapChain *swapchain;
6571 TRACE("Relaying to swapchain\n");
6573 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6575 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6576 IWineD3DSwapChain_Release(swapchain);
6580 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6581 IWineD3DSwapChain *swapchain;
6583 TRACE("Relaying to swapchain\n");
6585 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6586 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6587 IWineD3DSwapChain_Release(swapchain);
6592 /** ********************************************************
6593 * Notification functions
6594 ** ********************************************************/
6595 /** This function must be called in the release of a resource when ref == 0,
6596 * the contents of resource must still be correct,
6597 * any handles to other resource held by the caller must be closed
6598 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6599 *****************************************************/
6600 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6602 TRACE("(%p) : Adding resource %p\n", This, resource);
6604 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6607 static void device_resource_remove(struct IWineD3DDeviceImpl *device, struct IWineD3DResourceImpl *resource)
6609 TRACE("device %p, resource %p.\n", device, resource);
6611 list_remove(&resource->resource.resource_list_entry);
6614 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6616 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6617 unsigned int i;
6619 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6621 context_resource_released(device, resource, type);
6623 switch (type)
6625 case WINED3DRTYPE_SURFACE:
6626 if (!device->d3d_initialized) break;
6628 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6630 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6632 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6633 device->render_targets[i] = NULL;
6637 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6639 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6640 device->depth_stencil = NULL;
6642 break;
6644 case WINED3DRTYPE_TEXTURE:
6645 case WINED3DRTYPE_CUBETEXTURE:
6646 case WINED3DRTYPE_VOLUMETEXTURE:
6647 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6649 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6651 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6652 resource, device->stateBlock, i);
6653 device->stateBlock->state.textures[i] = NULL;
6656 if (device->updateStateBlock != device->stateBlock
6657 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6659 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6660 resource, device->updateStateBlock, i);
6661 device->updateStateBlock->state.textures[i] = NULL;
6664 break;
6666 case WINED3DRTYPE_BUFFER:
6667 for (i = 0; i < MAX_STREAMS; ++i)
6669 if (device->stateBlock
6670 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6672 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6673 resource, device->stateBlock, i);
6674 device->stateBlock->state.streams[i].buffer = NULL;
6677 if (device->updateStateBlock != device->stateBlock
6678 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6680 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6681 resource, device->updateStateBlock, i);
6682 device->updateStateBlock->state.streams[i].buffer = NULL;
6687 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6689 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6690 resource, device->stateBlock);
6691 device->stateBlock->state.index_buffer = NULL;
6694 if (device->updateStateBlock != device->stateBlock
6695 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6697 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6698 resource, device->updateStateBlock);
6699 device->updateStateBlock->state.index_buffer = NULL;
6701 break;
6703 default:
6704 break;
6707 /* Remove the resource from the resourceStore */
6708 device_resource_remove(device, (IWineD3DResourceImpl *)resource);
6710 TRACE("Resource released.\n");
6713 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6715 IWineD3DResourceImpl *resource, *cursor;
6716 HRESULT ret;
6717 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6719 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6720 TRACE("enumerating resource %p\n", resource);
6721 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6722 ret = pCallback((IWineD3DResource *) resource, pData);
6723 if(ret == S_FALSE) {
6724 TRACE("Canceling enumeration\n");
6725 break;
6728 return WINED3D_OK;
6731 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6734 IWineD3DResourceImpl *resource;
6736 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6738 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6739 if (type == WINED3DRTYPE_SURFACE)
6741 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6743 TRACE("Found surface %p for dc %p.\n", resource, dc);
6744 *surface = (IWineD3DSurface *)resource;
6745 return WINED3D_OK;
6750 return WINED3DERR_INVALIDCALL;
6753 /**********************************************************
6754 * IWineD3DDevice VTbl follows
6755 **********************************************************/
6757 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6759 /*** IUnknown methods ***/
6760 IWineD3DDeviceImpl_QueryInterface,
6761 IWineD3DDeviceImpl_AddRef,
6762 IWineD3DDeviceImpl_Release,
6763 /*** IWineD3DDevice methods ***/
6764 /*** Creation methods**/
6765 IWineD3DDeviceImpl_CreateBuffer,
6766 IWineD3DDeviceImpl_CreateVertexBuffer,
6767 IWineD3DDeviceImpl_CreateIndexBuffer,
6768 IWineD3DDeviceImpl_CreateStateBlock,
6769 IWineD3DDeviceImpl_CreateSurface,
6770 IWineD3DDeviceImpl_CreateRendertargetView,
6771 IWineD3DDeviceImpl_CreateTexture,
6772 IWineD3DDeviceImpl_CreateVolumeTexture,
6773 IWineD3DDeviceImpl_CreateVolume,
6774 IWineD3DDeviceImpl_CreateCubeTexture,
6775 IWineD3DDeviceImpl_CreateQuery,
6776 IWineD3DDeviceImpl_CreateSwapChain,
6777 IWineD3DDeviceImpl_CreateVertexDeclaration,
6778 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6779 IWineD3DDeviceImpl_CreateVertexShader,
6780 IWineD3DDeviceImpl_CreateGeometryShader,
6781 IWineD3DDeviceImpl_CreatePixelShader,
6782 IWineD3DDeviceImpl_CreatePalette,
6783 /*** Odd functions **/
6784 IWineD3DDeviceImpl_Init3D,
6785 IWineD3DDeviceImpl_InitGDI,
6786 IWineD3DDeviceImpl_Uninit3D,
6787 IWineD3DDeviceImpl_UninitGDI,
6788 IWineD3DDeviceImpl_SetMultithreaded,
6789 IWineD3DDeviceImpl_EvictManagedResources,
6790 IWineD3DDeviceImpl_GetAvailableTextureMem,
6791 IWineD3DDeviceImpl_GetBackBuffer,
6792 IWineD3DDeviceImpl_GetCreationParameters,
6793 IWineD3DDeviceImpl_GetDeviceCaps,
6794 IWineD3DDeviceImpl_GetDirect3D,
6795 IWineD3DDeviceImpl_GetDisplayMode,
6796 IWineD3DDeviceImpl_SetDisplayMode,
6797 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6798 IWineD3DDeviceImpl_GetRasterStatus,
6799 IWineD3DDeviceImpl_GetSwapChain,
6800 IWineD3DDeviceImpl_Reset,
6801 IWineD3DDeviceImpl_SetDialogBoxMode,
6802 IWineD3DDeviceImpl_SetCursorProperties,
6803 IWineD3DDeviceImpl_SetCursorPosition,
6804 IWineD3DDeviceImpl_ShowCursor,
6805 /*** Getters and setters **/
6806 IWineD3DDeviceImpl_SetClipPlane,
6807 IWineD3DDeviceImpl_GetClipPlane,
6808 IWineD3DDeviceImpl_SetClipStatus,
6809 IWineD3DDeviceImpl_GetClipStatus,
6810 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6811 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6812 IWineD3DDeviceImpl_SetDepthStencilSurface,
6813 IWineD3DDeviceImpl_GetDepthStencilSurface,
6814 IWineD3DDeviceImpl_SetGammaRamp,
6815 IWineD3DDeviceImpl_GetGammaRamp,
6816 IWineD3DDeviceImpl_SetIndexBuffer,
6817 IWineD3DDeviceImpl_GetIndexBuffer,
6818 IWineD3DDeviceImpl_SetBaseVertexIndex,
6819 IWineD3DDeviceImpl_GetBaseVertexIndex,
6820 IWineD3DDeviceImpl_SetLight,
6821 IWineD3DDeviceImpl_GetLight,
6822 IWineD3DDeviceImpl_SetLightEnable,
6823 IWineD3DDeviceImpl_GetLightEnable,
6824 IWineD3DDeviceImpl_SetMaterial,
6825 IWineD3DDeviceImpl_GetMaterial,
6826 IWineD3DDeviceImpl_SetNPatchMode,
6827 IWineD3DDeviceImpl_GetNPatchMode,
6828 IWineD3DDeviceImpl_SetPaletteEntries,
6829 IWineD3DDeviceImpl_GetPaletteEntries,
6830 IWineD3DDeviceImpl_SetPixelShader,
6831 IWineD3DDeviceImpl_GetPixelShader,
6832 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6833 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6834 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6835 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6836 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6837 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6838 IWineD3DDeviceImpl_SetRenderState,
6839 IWineD3DDeviceImpl_GetRenderState,
6840 IWineD3DDeviceImpl_SetRenderTarget,
6841 IWineD3DDeviceImpl_GetRenderTarget,
6842 IWineD3DDeviceImpl_SetSamplerState,
6843 IWineD3DDeviceImpl_GetSamplerState,
6844 IWineD3DDeviceImpl_SetScissorRect,
6845 IWineD3DDeviceImpl_GetScissorRect,
6846 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6847 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6848 IWineD3DDeviceImpl_SetStreamSource,
6849 IWineD3DDeviceImpl_GetStreamSource,
6850 IWineD3DDeviceImpl_SetStreamSourceFreq,
6851 IWineD3DDeviceImpl_GetStreamSourceFreq,
6852 IWineD3DDeviceImpl_SetTexture,
6853 IWineD3DDeviceImpl_GetTexture,
6854 IWineD3DDeviceImpl_SetTextureStageState,
6855 IWineD3DDeviceImpl_GetTextureStageState,
6856 IWineD3DDeviceImpl_SetTransform,
6857 IWineD3DDeviceImpl_GetTransform,
6858 IWineD3DDeviceImpl_SetVertexDeclaration,
6859 IWineD3DDeviceImpl_GetVertexDeclaration,
6860 IWineD3DDeviceImpl_SetVertexShader,
6861 IWineD3DDeviceImpl_GetVertexShader,
6862 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6863 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6864 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6865 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6866 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6867 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6868 IWineD3DDeviceImpl_SetViewport,
6869 IWineD3DDeviceImpl_GetViewport,
6870 IWineD3DDeviceImpl_MultiplyTransform,
6871 IWineD3DDeviceImpl_ValidateDevice,
6872 IWineD3DDeviceImpl_ProcessVertices,
6873 /*** State block ***/
6874 IWineD3DDeviceImpl_BeginStateBlock,
6875 IWineD3DDeviceImpl_EndStateBlock,
6876 /*** Scene management ***/
6877 IWineD3DDeviceImpl_BeginScene,
6878 IWineD3DDeviceImpl_EndScene,
6879 IWineD3DDeviceImpl_Present,
6880 IWineD3DDeviceImpl_Clear,
6881 IWineD3DDeviceImpl_ClearRendertargetView,
6882 /*** Drawing ***/
6883 IWineD3DDeviceImpl_SetPrimitiveType,
6884 IWineD3DDeviceImpl_GetPrimitiveType,
6885 IWineD3DDeviceImpl_DrawPrimitive,
6886 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6887 IWineD3DDeviceImpl_DrawPrimitiveUP,
6888 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6889 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6890 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6891 IWineD3DDeviceImpl_DrawRectPatch,
6892 IWineD3DDeviceImpl_DrawTriPatch,
6893 IWineD3DDeviceImpl_DeletePatch,
6894 IWineD3DDeviceImpl_ColorFill,
6895 IWineD3DDeviceImpl_UpdateTexture,
6896 IWineD3DDeviceImpl_UpdateSurface,
6897 IWineD3DDeviceImpl_GetFrontBufferData,
6898 /*** object tracking ***/
6899 IWineD3DDeviceImpl_EnumResources,
6900 IWineD3DDeviceImpl_GetSurfaceFromDC,
6901 IWineD3DDeviceImpl_AcquireFocusWindow,
6902 IWineD3DDeviceImpl_ReleaseFocusWindow,
6903 IWineD3DDeviceImpl_SetupFullscreenWindow,
6904 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6907 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6908 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6909 IWineD3DDeviceParent *device_parent)
6911 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6912 const struct fragment_pipeline *fragment_pipeline;
6913 struct shader_caps shader_caps;
6914 struct fragment_caps ffp_caps;
6915 WINED3DDISPLAYMODE mode;
6916 unsigned int i;
6917 HRESULT hr;
6919 device->lpVtbl = &IWineD3DDevice_Vtbl;
6920 device->ref = 1;
6921 device->wined3d = (IWineD3D *)wined3d;
6922 IWineD3D_AddRef(device->wined3d);
6923 device->adapter = wined3d->adapter_count ? adapter : NULL;
6924 device->device_parent = device_parent;
6925 list_init(&device->resources);
6926 list_init(&device->shaders);
6928 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6930 /* Get the initial screen setup for ddraw. */
6931 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6932 if (FAILED(hr))
6934 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6935 IWineD3D_Release(device->wined3d);
6936 return hr;
6938 device->ddraw_width = mode.Width;
6939 device->ddraw_height = mode.Height;
6940 device->ddraw_format = mode.Format;
6942 /* Save the creation parameters. */
6943 device->createParms.AdapterOrdinal = adapter_idx;
6944 device->createParms.DeviceType = device_type;
6945 device->createParms.hFocusWindow = focus_window;
6946 device->createParms.BehaviorFlags = flags;
6948 device->devType = device_type;
6949 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6951 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6952 device->shader_backend = adapter->shader_backend;
6954 if (device->shader_backend)
6956 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6957 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6958 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6959 device->vs_clipping = shader_caps.VSClipping;
6961 fragment_pipeline = adapter->fragment_pipe;
6962 device->frag_pipe = fragment_pipeline;
6963 if (fragment_pipeline)
6965 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6966 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6968 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6969 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6970 if (FAILED(hr))
6972 ERR("Failed to compile state table, hr %#x.\n", hr);
6973 IWineD3D_Release(device->wined3d);
6974 return hr;
6977 device->blitter = adapter->blitter;
6979 return WINED3D_OK;
6983 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6984 DWORD rep = This->StateTable[state].representative;
6985 struct wined3d_context *context;
6986 DWORD idx;
6987 BYTE shift;
6988 UINT i;
6990 for(i = 0; i < This->numContexts; i++) {
6991 context = This->contexts[i];
6992 if(isStateDirty(context, rep)) continue;
6994 context->dirtyArray[context->numDirtyEntries++] = rep;
6995 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6996 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6997 context->isStateDirty[idx] |= (1 << shift);
7001 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7003 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7004 *width = context->current_rt->pow2Width;
7005 *height = context->current_rt->pow2Height;
7008 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7010 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7011 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7012 * current context's drawable, which is the size of the back buffer of the swapchain
7013 * the active context belongs to. */
7014 *width = swapchain->presentParms.BackBufferWidth;
7015 *height = swapchain->presentParms.BackBufferHeight;
7018 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7019 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7021 if (device->filter_messages)
7023 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7024 window, message, wparam, lparam);
7025 if (unicode)
7026 return DefWindowProcW(window, message, wparam, lparam);
7027 else
7028 return DefWindowProcA(window, message, wparam, lparam);
7031 if (message == WM_DESTROY)
7033 TRACE("unregister window %p.\n", window);
7034 wined3d_unregister_window(window);
7036 if (device->focus_window == window) device->focus_window = NULL;
7037 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7040 if (unicode)
7041 return CallWindowProcW(proc, window, message, wparam, lparam);
7042 else
7043 return CallWindowProcA(proc, window, message, wparam, lparam);