wined3d: Use SetWindowPos() to make the focus window active.
[wine/multimedia.git] / dlls / wined3d / device.c
blob1263cbbe5eba29288555463218ffd18a02f161b9
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 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((IWineD3DBuffer *)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.internal_preload((IWineD3DBaseTexture *)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 HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1755 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1757 TRACE("iface %p, window %p.\n", iface, window);
1759 if (!wined3d_register_window(window, device))
1761 ERR("Failed to register window %p.\n", window);
1762 return E_FAIL;
1765 device->focus_window = window;
1766 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1768 return WINED3D_OK;
1771 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1773 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1775 TRACE("iface %p.\n", iface);
1777 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1778 device->focus_window = NULL;
1781 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1782 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1785 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1786 IWineD3DSwapChainImpl *swapchain = NULL;
1787 struct wined3d_context *context;
1788 HRESULT hr;
1789 DWORD state;
1790 unsigned int i;
1792 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1794 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1795 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1797 TRACE("(%p) : Creating stateblock\n", This);
1798 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1799 if (FAILED(hr))
1801 WARN("Failed to create stateblock\n");
1802 goto err_out;
1804 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1805 This->updateStateBlock = This->stateBlock;
1806 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1808 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1809 sizeof(*This->render_targets) * gl_info->limits.buffers);
1811 This->NumberOfPalettes = 1;
1812 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1813 if (!This->palettes || !This->render_targets)
1815 ERR("Out of memory!\n");
1816 hr = E_OUTOFMEMORY;
1817 goto err_out;
1819 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1820 if(!This->palettes[0]) {
1821 ERR("Out of memory!\n");
1822 hr = E_OUTOFMEMORY;
1823 goto err_out;
1825 for (i = 0; i < 256; ++i) {
1826 This->palettes[0][i].peRed = 0xFF;
1827 This->palettes[0][i].peGreen = 0xFF;
1828 This->palettes[0][i].peBlue = 0xFF;
1829 This->palettes[0][i].peFlags = 0xFF;
1831 This->currentPalette = 0;
1833 /* Initialize the texture unit mapping to a 1:1 mapping */
1834 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1836 if (state < gl_info->limits.fragment_samplers)
1838 This->texUnitMap[state] = state;
1839 This->rev_tex_unit_map[state] = state;
1840 } else {
1841 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1842 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1846 /* Setup the implicit swapchain. This also initializes a context. */
1847 TRACE("Creating implicit swapchain\n");
1848 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1849 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1850 if (FAILED(hr))
1852 WARN("Failed to create implicit swapchain\n");
1853 goto err_out;
1856 This->NumberOfSwapChains = 1;
1857 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1858 if(!This->swapchains) {
1859 ERR("Out of memory!\n");
1860 goto err_out;
1862 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1864 if (swapchain->back_buffers && swapchain->back_buffers[0])
1866 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1867 This->render_targets[0] = swapchain->back_buffers[0];
1869 else
1871 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1872 This->render_targets[0] = swapchain->front_buffer;
1874 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1876 /* Depth Stencil support */
1877 This->depth_stencil = This->auto_depth_stencil;
1878 if (This->depth_stencil)
1879 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1881 hr = This->shader_backend->shader_alloc_private(iface);
1882 if(FAILED(hr)) {
1883 TRACE("Shader private data couldn't be allocated\n");
1884 goto err_out;
1886 hr = This->frag_pipe->alloc_private(iface);
1887 if(FAILED(hr)) {
1888 TRACE("Fragment pipeline private data couldn't be allocated\n");
1889 goto err_out;
1891 hr = This->blitter->alloc_private(iface);
1892 if(FAILED(hr)) {
1893 TRACE("Blitter private data couldn't be allocated\n");
1894 goto err_out;
1897 /* Set up some starting GL setup */
1899 /* Setup all the devices defaults */
1900 stateblock_init_default_state(This->stateBlock);
1902 context = context_acquire(This, swapchain->front_buffer);
1904 create_dummy_textures(This);
1906 ENTER_GL();
1908 /* Initialize the current view state */
1909 This->view_ident = 1;
1910 This->contexts[0]->last_was_rhw = 0;
1911 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1912 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1914 switch(wined3d_settings.offscreen_rendering_mode) {
1915 case ORM_FBO:
1916 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1917 break;
1919 case ORM_BACKBUFFER:
1921 if (context_get_current()->aux_buffers > 0)
1923 TRACE("Using auxilliary buffer for offscreen rendering\n");
1924 This->offscreenBuffer = GL_AUX0;
1925 } else {
1926 TRACE("Using back buffer for offscreen rendering\n");
1927 This->offscreenBuffer = GL_BACK;
1932 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1933 LEAVE_GL();
1935 context_release(context);
1937 /* Clear the screen */
1938 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1939 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1940 0x00, 1.0f, 0);
1942 This->d3d_initialized = TRUE;
1944 if(wined3d_settings.logo) {
1945 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1947 This->highest_dirty_ps_const = 0;
1948 This->highest_dirty_vs_const = 0;
1949 return WINED3D_OK;
1951 err_out:
1952 HeapFree(GetProcessHeap(), 0, This->render_targets);
1953 HeapFree(GetProcessHeap(), 0, This->swapchains);
1954 This->NumberOfSwapChains = 0;
1955 if(This->palettes) {
1956 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1957 HeapFree(GetProcessHeap(), 0, This->palettes);
1959 This->NumberOfPalettes = 0;
1960 if(swapchain) {
1961 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1963 if(This->stateBlock) {
1964 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1965 This->stateBlock = NULL;
1967 if (This->blit_priv) {
1968 This->blitter->free_private(iface);
1970 if (This->fragment_priv) {
1971 This->frag_pipe->free_private(iface);
1973 if (This->shader_priv) {
1974 This->shader_backend->shader_free_private(iface);
1976 return hr;
1979 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1980 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1983 IWineD3DSwapChainImpl *swapchain = NULL;
1984 HRESULT hr;
1986 /* Setup the implicit swapchain */
1987 TRACE("Creating implicit swapchain\n");
1988 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1989 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1990 if (FAILED(hr))
1992 WARN("Failed to create implicit swapchain\n");
1993 goto err_out;
1996 This->NumberOfSwapChains = 1;
1997 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1998 if(!This->swapchains) {
1999 ERR("Out of memory!\n");
2000 goto err_out;
2002 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2003 return WINED3D_OK;
2005 err_out:
2006 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2007 return hr;
2010 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2012 IWineD3DResource_UnLoad(resource);
2013 IWineD3DResource_Release(resource);
2014 return WINED3D_OK;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2018 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2021 const struct wined3d_gl_info *gl_info;
2022 struct wined3d_context *context;
2023 int sampler;
2024 UINT i;
2025 TRACE("(%p)\n", This);
2027 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2029 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2030 * it was created. Thus make sure a context is active for the glDelete* calls
2032 context = context_acquire(This, NULL);
2033 gl_info = context->gl_info;
2035 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2037 /* Unload resources */
2038 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2040 TRACE("Deleting high order patches\n");
2041 for(i = 0; i < PATCHMAP_SIZE; i++) {
2042 struct list *e1, *e2;
2043 struct WineD3DRectPatch *patch;
2044 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2045 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2046 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2050 /* Delete the mouse cursor texture */
2051 if(This->cursorTexture) {
2052 ENTER_GL();
2053 glDeleteTextures(1, &This->cursorTexture);
2054 LEAVE_GL();
2055 This->cursorTexture = 0;
2058 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2059 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2061 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2062 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2065 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2066 * private data, it might contain opengl pointers
2068 if(This->depth_blt_texture) {
2069 ENTER_GL();
2070 glDeleteTextures(1, &This->depth_blt_texture);
2071 LEAVE_GL();
2072 This->depth_blt_texture = 0;
2074 if (This->depth_blt_rb) {
2075 ENTER_GL();
2076 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2077 LEAVE_GL();
2078 This->depth_blt_rb = 0;
2079 This->depth_blt_rb_w = 0;
2080 This->depth_blt_rb_h = 0;
2083 /* Release the update stateblock */
2084 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2085 if(This->updateStateBlock != This->stateBlock)
2086 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2088 This->updateStateBlock = NULL;
2090 { /* because were not doing proper internal refcounts releasing the primary state block
2091 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2092 to set this->stateBlock = NULL; first */
2093 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2094 This->stateBlock = NULL;
2096 /* Release the stateblock */
2097 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2098 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2102 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2103 This->blitter->free_private(iface);
2104 This->frag_pipe->free_private(iface);
2105 This->shader_backend->shader_free_private(iface);
2107 /* Release the buffers (with sanity checks)*/
2108 if (This->onscreen_depth_stencil)
2110 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2111 This->onscreen_depth_stencil = NULL;
2114 if (This->depth_stencil)
2116 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2118 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2120 This->depth_stencil = NULL;
2121 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2122 && ds != This->auto_depth_stencil)
2124 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2128 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2129 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2131 TRACE("Setting rendertarget to NULL\n");
2132 This->render_targets[0] = NULL;
2134 if (This->auto_depth_stencil)
2136 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2138 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2140 This->auto_depth_stencil = NULL;
2143 context_release(context);
2145 for(i=0; i < This->NumberOfSwapChains; i++) {
2146 TRACE("Releasing the implicit swapchain %d\n", i);
2147 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2148 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2152 HeapFree(GetProcessHeap(), 0, This->swapchains);
2153 This->swapchains = NULL;
2154 This->NumberOfSwapChains = 0;
2156 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2157 HeapFree(GetProcessHeap(), 0, This->palettes);
2158 This->palettes = NULL;
2159 This->NumberOfPalettes = 0;
2161 HeapFree(GetProcessHeap(), 0, This->render_targets);
2162 This->render_targets = NULL;
2164 This->d3d_initialized = FALSE;
2166 return WINED3D_OK;
2169 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2171 unsigned int i;
2173 for(i=0; i < This->NumberOfSwapChains; i++) {
2174 TRACE("Releasing the implicit swapchain %d\n", i);
2175 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2176 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2180 HeapFree(GetProcessHeap(), 0, This->swapchains);
2181 This->swapchains = NULL;
2182 This->NumberOfSwapChains = 0;
2183 return WINED3D_OK;
2186 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2187 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2188 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2190 * There is no way to deactivate thread safety once it is enabled.
2192 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2195 /*For now just store the flag(needed in case of ddraw) */
2196 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2199 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2200 const WINED3DDISPLAYMODE* pMode) {
2201 DEVMODEW devmode;
2202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2203 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2204 LONG ret;
2205 RECT clip_rc;
2207 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2209 /* Resize the screen even without a window:
2210 * The app could have unset it with SetCooperativeLevel, but not called
2211 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2212 * but we don't have any hwnd
2215 memset(&devmode, 0, sizeof(devmode));
2216 devmode.dmSize = sizeof(devmode);
2217 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2218 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2219 devmode.dmPelsWidth = pMode->Width;
2220 devmode.dmPelsHeight = pMode->Height;
2222 devmode.dmDisplayFrequency = pMode->RefreshRate;
2223 if (pMode->RefreshRate)
2224 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2226 /* Only change the mode if necessary */
2227 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2228 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2229 return WINED3D_OK;
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2232 if (ret != DISP_CHANGE_SUCCESSFUL)
2234 if (devmode.dmDisplayFrequency)
2236 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2237 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2238 devmode.dmDisplayFrequency = 0;
2239 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2241 if(ret != DISP_CHANGE_SUCCESSFUL) {
2242 return WINED3DERR_NOTAVAILABLE;
2246 /* Store the new values */
2247 This->ddraw_width = pMode->Width;
2248 This->ddraw_height = pMode->Height;
2249 This->ddraw_format = pMode->Format;
2251 /* And finally clip mouse to our screen */
2252 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2253 ClipCursor(&clip_rc);
2255 return WINED3D_OK;
2258 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 *ppD3D = This->wined3d;
2261 TRACE("Returning %p.\n", *ppD3D);
2262 IWineD3D_AddRef(*ppD3D);
2263 return WINED3D_OK;
2266 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2269 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2270 (This->adapter->TextureRam/(1024*1024)),
2271 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2272 /* return simulated texture memory left */
2273 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2276 /*****
2277 * Get / Set Stream Source
2278 *****/
2279 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2280 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 struct wined3d_stream_state *stream;
2284 IWineD3DBuffer *oldSrc;
2286 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2287 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2289 if (StreamNumber >= MAX_STREAMS) {
2290 WARN("Stream out of range %d\n", StreamNumber);
2291 return WINED3DERR_INVALIDCALL;
2292 } else if(OffsetInBytes & 0x3) {
2293 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2294 return WINED3DERR_INVALIDCALL;
2297 stream = &This->updateStateBlock->state.streams[StreamNumber];
2298 oldSrc = (IWineD3DBuffer *)stream->buffer;
2300 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2302 if (oldSrc == pStreamData
2303 && stream->stride == Stride
2304 && stream->offset == OffsetInBytes)
2306 TRACE("Application is setting the old values over, nothing to do\n");
2307 return WINED3D_OK;
2310 stream->buffer = (struct wined3d_buffer *)pStreamData;
2311 if (pStreamData)
2313 stream->stride = Stride;
2314 stream->offset = OffsetInBytes;
2317 /* Handle recording of state blocks */
2318 if (This->isRecordingState) {
2319 TRACE("Recording... not performing anything\n");
2320 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2321 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2322 return WINED3D_OK;
2325 if (pStreamData)
2327 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2328 IWineD3DBuffer_AddRef(pStreamData);
2330 if (oldSrc)
2332 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2333 IWineD3DBuffer_Release(oldSrc);
2336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2338 return WINED3D_OK;
2341 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2342 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 struct wined3d_stream_state *stream;
2347 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2348 iface, StreamNumber, pStream, pOffset, pStride);
2350 if (StreamNumber >= MAX_STREAMS)
2352 WARN("Stream out of range %d\n", StreamNumber);
2353 return WINED3DERR_INVALIDCALL;
2356 stream = &This->stateBlock->state.streams[StreamNumber];
2357 *pStream = (IWineD3DBuffer *)stream->buffer;
2358 *pStride = stream->stride;
2359 if (pOffset) *pOffset = stream->offset;
2361 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2363 return WINED3D_OK;
2366 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 struct wined3d_stream_state *stream;
2369 UINT oldFlags, oldFreq;
2371 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2373 /* Verify input at least in d3d9 this is invalid. */
2374 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2376 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2377 return WINED3DERR_INVALIDCALL;
2379 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2381 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2382 return WINED3DERR_INVALIDCALL;
2384 if (!Divider)
2386 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2387 return WINED3DERR_INVALIDCALL;
2390 stream = &This->updateStateBlock->state.streams[StreamNumber];
2391 oldFlags = stream->flags;
2392 oldFreq = stream->frequency;
2394 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2395 stream->frequency = Divider & 0x7FFFFF;
2397 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2399 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2402 return WINED3D_OK;
2405 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2407 struct wined3d_stream_state *stream;
2409 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2411 stream = &This->updateStateBlock->state.streams[StreamNumber];
2412 *Divider = stream->flags | stream->frequency;
2414 TRACE("Returning %#x.\n", *Divider);
2416 return WINED3D_OK;
2419 /*****
2420 * Get / Set & Multiply Transform
2421 *****/
2422 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 /* Most of this routine, comments included copied from ddraw tree initially: */
2426 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2428 /* Handle recording of state blocks */
2429 if (This->isRecordingState) {
2430 TRACE("Recording... not performing anything\n");
2431 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2432 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2433 return WINED3D_OK;
2437 * If the new matrix is the same as the current one,
2438 * we cut off any further processing. this seems to be a reasonable
2439 * optimization because as was noticed, some apps (warcraft3 for example)
2440 * tend towards setting the same matrix repeatedly for some reason.
2442 * From here on we assume that the new matrix is different, wherever it matters.
2444 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2446 TRACE("The app is setting the same matrix over again\n");
2447 return WINED3D_OK;
2449 else
2451 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2455 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2456 where ViewMat = Camera space, WorldMat = world space.
2458 In OpenGL, camera and world space is combined into GL_MODELVIEW
2459 matrix. The Projection matrix stay projection matrix.
2462 /* Capture the times we can just ignore the change for now */
2463 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2464 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2465 /* Handled by the state manager */
2468 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2471 return WINED3D_OK;
2475 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2476 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2478 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2480 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2482 *matrix = device->stateBlock->state.transforms[state];
2484 return WINED3D_OK;
2487 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2488 const WINED3DMATRIX *mat = NULL;
2489 WINED3DMATRIX temp;
2491 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2492 * below means it will be recorded in a state block change, but it
2493 * works regardless where it is recorded.
2494 * If this is found to be wrong, change to StateBlock.
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2499 if (State <= HIGHEST_TRANSFORMSTATE)
2501 mat = &This->updateStateBlock->state.transforms[State];
2503 else
2505 FIXME("Unhandled transform state!!\n");
2508 multiply_matrix(&temp, mat, pMatrix);
2510 /* Apply change via set transform - will reapply to eg. lights this way */
2511 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2514 /*****
2515 * Get / Set Light
2516 *****/
2517 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2518 you can reference any indexes you want as long as that number max are enabled at any
2519 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2520 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2521 but when recording, just build a chain pretty much of commands to be replayed. */
2523 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2524 float rho;
2525 struct wined3d_light_info *object = NULL;
2526 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2527 struct list *e;
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2532 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2533 * the gl driver.
2535 if(!pLight) {
2536 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2537 return WINED3DERR_INVALIDCALL;
2540 switch(pLight->Type) {
2541 case WINED3DLIGHT_POINT:
2542 case WINED3DLIGHT_SPOT:
2543 case WINED3DLIGHT_PARALLELPOINT:
2544 case WINED3DLIGHT_GLSPOT:
2545 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2546 * most wanted
2548 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2550 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2551 return WINED3DERR_INVALIDCALL;
2553 break;
2555 case WINED3DLIGHT_DIRECTIONAL:
2556 /* Ignores attenuation */
2557 break;
2559 default:
2560 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2561 return WINED3DERR_INVALIDCALL;
2564 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2566 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2567 if(object->OriginalIndex == Index) break;
2568 object = NULL;
2571 if(!object) {
2572 TRACE("Adding new light\n");
2573 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2574 if(!object) {
2575 ERR("Out of memory error when allocating a light\n");
2576 return E_OUTOFMEMORY;
2578 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2579 object->glIndex = -1;
2580 object->OriginalIndex = Index;
2583 /* Initialize the object */
2584 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,
2585 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2586 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2587 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2588 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2589 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2590 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2592 /* Save away the information */
2593 object->OriginalParms = *pLight;
2595 switch (pLight->Type) {
2596 case WINED3DLIGHT_POINT:
2597 /* Position */
2598 object->lightPosn[0] = pLight->Position.x;
2599 object->lightPosn[1] = pLight->Position.y;
2600 object->lightPosn[2] = pLight->Position.z;
2601 object->lightPosn[3] = 1.0f;
2602 object->cutoff = 180.0f;
2603 /* FIXME: Range */
2604 break;
2606 case WINED3DLIGHT_DIRECTIONAL:
2607 /* Direction */
2608 object->lightPosn[0] = -pLight->Direction.x;
2609 object->lightPosn[1] = -pLight->Direction.y;
2610 object->lightPosn[2] = -pLight->Direction.z;
2611 object->lightPosn[3] = 0.0f;
2612 object->exponent = 0.0f;
2613 object->cutoff = 180.0f;
2614 break;
2616 case WINED3DLIGHT_SPOT:
2617 /* Position */
2618 object->lightPosn[0] = pLight->Position.x;
2619 object->lightPosn[1] = pLight->Position.y;
2620 object->lightPosn[2] = pLight->Position.z;
2621 object->lightPosn[3] = 1.0f;
2623 /* Direction */
2624 object->lightDirn[0] = pLight->Direction.x;
2625 object->lightDirn[1] = pLight->Direction.y;
2626 object->lightDirn[2] = pLight->Direction.z;
2627 object->lightDirn[3] = 1.0f;
2630 * opengl-ish and d3d-ish spot lights use too different models for the
2631 * light "intensity" as a function of the angle towards the main light direction,
2632 * so we only can approximate very roughly.
2633 * however spot lights are rather rarely used in games (if ever used at all).
2634 * furthermore if still used, probably nobody pays attention to such details.
2636 if (!pLight->Falloff)
2638 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2639 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2640 * will always be 1.0 for both of them, and we don't have to care for the
2641 * rest of the rather complex calculation
2643 object->exponent = 0.0f;
2644 } else {
2645 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2646 if (rho < 0.0001f) rho = 0.0001f;
2647 object->exponent = -0.3f/logf(cosf(rho/2));
2649 if (object->exponent > 128.0f)
2651 object->exponent = 128.0f;
2653 object->cutoff = (float) (pLight->Phi*90/M_PI);
2655 /* FIXME: Range */
2656 break;
2658 default:
2659 FIXME("Unrecognized light type %d\n", pLight->Type);
2662 /* Update the live definitions if the light is currently assigned a glIndex */
2663 if (object->glIndex != -1 && !This->isRecordingState) {
2664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2666 return WINED3D_OK;
2669 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2671 struct wined3d_light_info *lightInfo = NULL;
2672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2674 struct list *e;
2675 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2677 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2679 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2680 if(lightInfo->OriginalIndex == Index) break;
2681 lightInfo = NULL;
2684 if (!lightInfo)
2686 TRACE("Light information requested but light not defined\n");
2687 return WINED3DERR_INVALIDCALL;
2690 *pLight = lightInfo->OriginalParms;
2691 return WINED3D_OK;
2694 /*****
2695 * Get / Set Light Enable
2696 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2697 *****/
2698 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2700 struct wined3d_light_info *lightInfo = NULL;
2701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2702 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2703 struct list *e;
2704 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2706 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2708 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2709 if(lightInfo->OriginalIndex == Index) break;
2710 lightInfo = NULL;
2712 TRACE("Found light: %p\n", lightInfo);
2714 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2715 if (!lightInfo)
2717 TRACE("Light enabled requested but light not defined, so defining one!\n");
2718 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2720 /* Search for it again! Should be fairly quick as near head of list */
2721 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2723 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2724 if(lightInfo->OriginalIndex == Index) break;
2725 lightInfo = NULL;
2727 if (!lightInfo)
2729 FIXME("Adding default lights has failed dismally\n");
2730 return WINED3DERR_INVALIDCALL;
2734 if(!Enable) {
2735 if(lightInfo->glIndex != -1) {
2736 if(!This->isRecordingState) {
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2740 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2741 lightInfo->glIndex = -1;
2742 } else {
2743 TRACE("Light already disabled, nothing to do\n");
2745 lightInfo->enabled = FALSE;
2746 } else {
2747 lightInfo->enabled = TRUE;
2748 if (lightInfo->glIndex != -1) {
2749 /* nop */
2750 TRACE("Nothing to do as light was enabled\n");
2751 } else {
2752 int i;
2753 /* Find a free gl light */
2754 for (i = 0; i < This->maxConcurrentLights; ++i)
2756 if (!This->updateStateBlock->state.lights[i])
2758 This->updateStateBlock->state.lights[i] = lightInfo;
2759 lightInfo->glIndex = i;
2760 break;
2763 if(lightInfo->glIndex == -1) {
2764 /* Our tests show that Windows returns D3D_OK in this situation, even with
2765 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2766 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2767 * as well for those lights.
2769 * TODO: Test how this affects rendering
2771 WARN("Too many concurrently active lights\n");
2772 return WINED3D_OK;
2775 /* i == lightInfo->glIndex */
2776 if(!This->isRecordingState) {
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2782 return WINED3D_OK;
2785 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2787 struct wined3d_light_info *lightInfo = NULL;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 struct list *e;
2790 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2791 TRACE("(%p) : for idx(%d)\n", This, Index);
2793 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2795 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2796 if(lightInfo->OriginalIndex == Index) break;
2797 lightInfo = NULL;
2800 if (!lightInfo)
2802 TRACE("Light enabled state requested but light not defined\n");
2803 return WINED3DERR_INVALIDCALL;
2805 /* true is 128 according to SetLightEnable */
2806 *pEnable = lightInfo->enabled ? 128 : 0;
2807 return WINED3D_OK;
2810 /*****
2811 * Get / Set Clip Planes
2812 *****/
2813 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2815 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2817 /* Validate Index */
2818 if (Index >= This->adapter->gl_info.limits.clipplanes)
2820 TRACE("Application has requested clipplane this device doesn't support\n");
2821 return WINED3DERR_INVALIDCALL;
2824 This->updateStateBlock->changed.clipplane |= 1 << Index;
2826 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2827 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2828 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2829 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2831 TRACE("Application is setting old values over, nothing to do\n");
2832 return WINED3D_OK;
2835 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2836 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2837 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2838 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2840 /* Handle recording of state blocks */
2841 if (This->isRecordingState) {
2842 TRACE("Recording... not performing anything\n");
2843 return WINED3D_OK;
2846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2848 return WINED3D_OK;
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 TRACE("(%p) : for idx %d\n", This, Index);
2855 /* Validate Index */
2856 if (Index >= This->adapter->gl_info.limits.clipplanes)
2858 TRACE("Application has requested clipplane this device doesn't support\n");
2859 return WINED3DERR_INVALIDCALL;
2862 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2863 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2864 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2865 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2866 return WINED3D_OK;
2869 /*****
2870 * Get / Set Clip Plane Status
2871 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2872 *****/
2873 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 FIXME("(%p) : stub\n", This);
2877 if (!pClipStatus)
2878 return WINED3DERR_INVALIDCALL;
2880 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2881 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 FIXME("(%p) : stub\n", This);
2889 if (!pClipStatus)
2890 return WINED3DERR_INVALIDCALL;
2892 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2893 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2894 return WINED3D_OK;
2897 /*****
2898 * Get / Set Material
2899 *****/
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 This->updateStateBlock->changed.material = TRUE;
2904 This->updateStateBlock->state.material = *pMaterial;
2906 /* Handle recording of state blocks */
2907 if (This->isRecordingState) {
2908 TRACE("Recording... not performing anything\n");
2909 return WINED3D_OK;
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2913 return WINED3D_OK;
2916 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 *pMaterial = This->updateStateBlock->state.material;
2919 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2920 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2921 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2922 pMaterial->Ambient.b, pMaterial->Ambient.a);
2923 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2924 pMaterial->Specular.b, pMaterial->Specular.a);
2925 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2926 pMaterial->Emissive.b, pMaterial->Emissive.a);
2927 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2929 return WINED3D_OK;
2932 /*****
2933 * Get / Set Indices
2934 *****/
2935 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2936 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2939 IWineD3DBuffer *oldIdxs;
2941 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2942 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2944 This->updateStateBlock->changed.indices = TRUE;
2945 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2946 This->updateStateBlock->state.index_format = fmt;
2948 /* Handle recording of state blocks */
2949 if (This->isRecordingState) {
2950 TRACE("Recording... not performing anything\n");
2951 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2952 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2953 return WINED3D_OK;
2956 if(oldIdxs != pIndexData) {
2957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2958 if(pIndexData) {
2959 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2960 IWineD3DBuffer_AddRef(pIndexData);
2962 if(oldIdxs) {
2963 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2964 IWineD3DBuffer_Release(oldIdxs);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2977 /* up ref count on ppindexdata */
2978 if (*ppIndexData) {
2979 IWineD3DBuffer_AddRef(*ppIndexData);
2980 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2981 }else{
2982 TRACE("(%p) No index data set\n", This);
2984 TRACE("Returning %p\n", *ppIndexData);
2986 return WINED3D_OK;
2989 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 TRACE("(%p)->(%d)\n", This, BaseIndex);
2994 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2996 TRACE("Application is setting the old value over, nothing to do\n");
2997 return WINED3D_OK;
3000 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3002 if (This->isRecordingState) {
3003 TRACE("Recording... not performing anything\n");
3004 return WINED3D_OK;
3006 /* The base vertex index affects the stream sources */
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p) : base_index %p\n", This, base_index);
3015 *base_index = This->stateBlock->state.base_vertex_index;
3017 TRACE("Returning %u\n", *base_index);
3019 return WINED3D_OK;
3022 /*****
3023 * Get / Set Viewports
3024 *****/
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 TRACE("(%p)\n", This);
3029 This->updateStateBlock->changed.viewport = TRUE;
3030 This->updateStateBlock->state.viewport = *pViewport;
3032 /* Handle recording of state blocks */
3033 if (This->isRecordingState) {
3034 TRACE("Recording... not performing anything\n");
3035 return WINED3D_OK;
3038 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3039 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3042 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3048 TRACE("(%p)\n", This);
3049 *pViewport = This->stateBlock->state.viewport;
3050 return WINED3D_OK;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3054 WINED3DRENDERSTATETYPE State, DWORD Value)
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 DWORD oldValue = This->stateBlock->state.render_states[State];
3059 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3061 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3062 This->updateStateBlock->state.render_states[State] = Value;
3064 /* Handle recording of state blocks */
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 return WINED3D_OK;
3070 /* Compared here and not before the assignment to allow proper stateblock recording */
3071 if(Value == oldValue) {
3072 TRACE("Application is setting the old value over, nothing to do\n");
3073 } else {
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3081 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3087 *pValue = This->stateBlock->state.render_states[State];
3088 return WINED3D_OK;
3091 /*****
3092 * Get / Set Sampler States
3093 * TODO: Verify against dx9 definitions
3094 *****/
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 DWORD oldValue;
3100 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3101 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3103 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3104 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3107 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3109 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3110 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3113 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3114 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3115 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3117 /* Handle recording of state blocks */
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3123 if(oldValue == Value) {
3124 TRACE("Application is setting the old value over, nothing to do\n");
3125 return WINED3D_OK;
3128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3130 return WINED3D_OK;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3137 This, Sampler, debug_d3dsamplerstate(Type), Type);
3139 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3140 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3143 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3145 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3146 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3148 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3149 TRACE("(%p) : Returning %#x\n", This, *Value);
3151 return WINED3D_OK;
3154 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 This->updateStateBlock->changed.scissorRect = TRUE;
3158 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3160 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3161 return WINED3D_OK;
3163 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3165 if(This->isRecordingState) {
3166 TRACE("Recording... not performing anything\n");
3167 return WINED3D_OK;
3170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3172 return WINED3D_OK;
3175 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 *pRect = This->updateStateBlock->state.scissor_rect;
3179 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3180 return WINED3D_OK;
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3185 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3187 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3189 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3190 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3192 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3193 This->updateStateBlock->changed.vertexDecl = TRUE;
3195 if (This->isRecordingState) {
3196 TRACE("Recording... not performing anything\n");
3197 return WINED3D_OK;
3198 } else if(pDecl == oldDecl) {
3199 /* Checked after the assignment to allow proper stateblock recording */
3200 TRACE("Application is setting the old declaration over, nothing to do\n");
3201 return WINED3D_OK;
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3205 return WINED3D_OK;
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3213 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3214 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3215 return WINED3D_OK;
3218 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3223 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3224 This->updateStateBlock->changed.vertexShader = TRUE;
3226 if (This->isRecordingState) {
3227 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3228 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3229 TRACE("Recording... not performing anything\n");
3230 return WINED3D_OK;
3231 } else if(oldShader == pShader) {
3232 /* Checked here to allow proper stateblock recording */
3233 TRACE("App is setting the old shader over, nothing to do\n");
3234 return WINED3D_OK;
3237 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3238 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3239 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3243 return WINED3D_OK;
3246 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3248 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3249 IWineD3DVertexShader *shader;
3251 TRACE("iface %p.\n", iface);
3253 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3254 if (shader) IWineD3DVertexShader_AddRef(shader);
3256 TRACE("Returning %p.\n", shader);
3257 return shader;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3261 IWineD3DDevice *iface,
3262 UINT start,
3263 CONST BOOL *srcData,
3264 UINT count) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3269 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3270 iface, srcData, start, count);
3272 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3274 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3275 for (i = 0; i < cnt; i++)
3276 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3278 for (i = start; i < cnt + start; ++i) {
3279 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3282 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3284 return WINED3D_OK;
3287 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3288 IWineD3DDevice *iface,
3289 UINT start,
3290 BOOL *dstData,
3291 UINT count) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int cnt = min(count, MAX_CONST_B - start);
3296 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3297 iface, dstData, start, count);
3299 if (!dstData || cnt < 0)
3300 return WINED3DERR_INVALIDCALL;
3302 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3303 return WINED3D_OK;
3306 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3307 IWineD3DDevice *iface,
3308 UINT start,
3309 CONST int *srcData,
3310 UINT count) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3313 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3315 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3316 iface, srcData, start, count);
3318 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3320 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3321 for (i = 0; i < cnt; i++)
3322 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3323 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3325 for (i = start; i < cnt + start; ++i) {
3326 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3329 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3331 return WINED3D_OK;
3334 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3335 IWineD3DDevice *iface,
3336 UINT start,
3337 int *dstData,
3338 UINT count) {
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341 int cnt = min(count, MAX_CONST_I - start);
3343 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3344 iface, dstData, start, count);
3346 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3347 return WINED3DERR_INVALIDCALL;
3349 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3350 return WINED3D_OK;
3353 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3354 IWineD3DDevice *iface,
3355 UINT start,
3356 CONST float *srcData,
3357 UINT count) {
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3360 UINT i;
3362 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3363 iface, srcData, start, count);
3365 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3366 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3367 return WINED3DERR_INVALIDCALL;
3369 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3370 if(TRACE_ON(d3d)) {
3371 for (i = 0; i < count; i++)
3372 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3373 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3376 if (!This->isRecordingState)
3378 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3382 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3383 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3385 return WINED3D_OK;
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3389 IWineD3DDevice *iface,
3390 UINT start,
3391 float *dstData,
3392 UINT count) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 int cnt = min(count, This->d3d_vshader_constantF - start);
3397 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3398 iface, dstData, start, count);
3400 if (!dstData || cnt < 0)
3401 return WINED3DERR_INVALIDCALL;
3403 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3404 return WINED3D_OK;
3407 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3408 DWORD i;
3409 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3415 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3417 DWORD i = This->rev_tex_unit_map[unit];
3418 DWORD j = This->texUnitMap[stage];
3420 This->texUnitMap[stage] = unit;
3421 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3423 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3426 This->rev_tex_unit_map[unit] = stage;
3427 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3429 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3433 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3434 int i;
3436 This->fixed_function_usage_map = 0;
3437 for (i = 0; i < MAX_TEXTURES; ++i)
3439 const struct wined3d_state *state = &This->stateBlock->state;
3440 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3441 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3442 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3443 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3444 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3445 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3446 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3447 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3449 if (color_op == WINED3DTOP_DISABLE) {
3450 /* Not used, and disable higher stages */
3451 break;
3454 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3455 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3456 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3457 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3458 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3459 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3460 This->fixed_function_usage_map |= (1 << i);
3463 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3464 This->fixed_function_usage_map |= (1 << (i + 1));
3469 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3471 unsigned int i, tex;
3472 WORD ffu_map;
3474 device_update_fixed_function_usage_map(This);
3475 ffu_map = This->fixed_function_usage_map;
3477 if (This->max_ffp_textures == gl_info->limits.texture_stages
3478 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3480 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3482 if (!(ffu_map & 1)) continue;
3484 if (This->texUnitMap[i] != i) {
3485 device_map_stage(This, i, i);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3487 markTextureStagesDirty(This, i);
3490 return;
3493 /* Now work out the mapping */
3494 tex = 0;
3495 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3497 if (!(ffu_map & 1)) continue;
3499 if (This->texUnitMap[i] != tex) {
3500 device_map_stage(This, i, tex);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 markTextureStagesDirty(This, i);
3505 ++tex;
3509 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3511 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3512 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3513 unsigned int i;
3515 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3516 if (sampler_type[i] && This->texUnitMap[i] != i)
3518 device_map_stage(This, i, i);
3519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3520 if (i < gl_info->limits.texture_stages)
3522 markTextureStagesDirty(This, i);
3528 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3529 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3531 DWORD current_mapping = This->rev_tex_unit_map[unit];
3533 /* Not currently used */
3534 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3536 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3537 /* Used by a fragment sampler */
3539 if (!pshader_sampler_tokens) {
3540 /* No pixel shader, check fixed function */
3541 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3544 /* Pixel shader, check the shader's sampler map */
3545 return !pshader_sampler_tokens[current_mapping];
3548 /* Used by a vertex sampler */
3549 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3552 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3554 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3555 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3556 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3557 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3558 int i;
3560 if (ps)
3562 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3564 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3565 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3566 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3569 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3570 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3571 if (vshader_sampler_type[i])
3573 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3575 /* Already mapped somewhere */
3576 continue;
3579 while (start >= 0) {
3580 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3582 device_map_stage(This, vsampler_idx, start);
3583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3585 --start;
3586 break;
3589 --start;
3595 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3597 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3598 const struct wined3d_state *state = &This->stateBlock->state;
3599 BOOL vs = use_vs(state);
3600 BOOL ps = use_ps(state);
3602 * Rules are:
3603 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3604 * that would be really messy and require shader recompilation
3605 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3606 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3608 if (ps) device_map_psamplers(This, gl_info);
3609 else device_map_fixed_function_samplers(This, gl_info);
3611 if (vs) device_map_vsamplers(This, ps, gl_info);
3614 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3618 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3619 This->updateStateBlock->changed.pixelShader = TRUE;
3621 /* Handle recording of state blocks */
3622 if (This->isRecordingState) {
3623 TRACE("Recording... not performing anything\n");
3626 if (This->isRecordingState) {
3627 TRACE("Recording... not performing anything\n");
3628 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3629 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3630 return WINED3D_OK;
3633 if(pShader == oldShader) {
3634 TRACE("App is setting the old pixel shader over, nothing to do\n");
3635 return WINED3D_OK;
3638 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3639 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3641 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3644 return WINED3D_OK;
3647 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3649 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3650 IWineD3DPixelShader *shader;
3652 TRACE("iface %p.\n", iface);
3654 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3655 if (shader) IWineD3DPixelShader_AddRef(shader);
3657 TRACE("Returning %p.\n", shader);
3658 return shader;
3661 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3662 IWineD3DDevice *iface,
3663 UINT start,
3664 CONST BOOL *srcData,
3665 UINT count) {
3667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3668 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3670 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3671 iface, srcData, start, count);
3673 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3675 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3676 for (i = 0; i < cnt; i++)
3677 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3679 for (i = start; i < cnt + start; ++i) {
3680 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3683 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3685 return WINED3D_OK;
3688 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3689 IWineD3DDevice *iface,
3690 UINT start,
3691 BOOL *dstData,
3692 UINT count) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 int cnt = min(count, MAX_CONST_B - start);
3697 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3698 iface, dstData, start, count);
3700 if (!dstData || cnt < 0)
3701 return WINED3DERR_INVALIDCALL;
3703 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3704 return WINED3D_OK;
3707 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3708 IWineD3DDevice *iface,
3709 UINT start,
3710 CONST int *srcData,
3711 UINT count) {
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3716 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3717 iface, srcData, start, count);
3719 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3721 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3722 for (i = 0; i < cnt; i++)
3723 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3724 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3726 for (i = start; i < cnt + start; ++i) {
3727 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3730 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3732 return WINED3D_OK;
3735 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3736 IWineD3DDevice *iface,
3737 UINT start,
3738 int *dstData,
3739 UINT count) {
3741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3742 int cnt = min(count, MAX_CONST_I - start);
3744 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3745 iface, dstData, start, count);
3747 if (!dstData || cnt < 0)
3748 return WINED3DERR_INVALIDCALL;
3750 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3751 return WINED3D_OK;
3754 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3755 IWineD3DDevice *iface,
3756 UINT start,
3757 CONST float *srcData,
3758 UINT count) {
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 UINT i;
3763 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3764 iface, srcData, start, count);
3766 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3767 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3768 return WINED3DERR_INVALIDCALL;
3770 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3771 if(TRACE_ON(d3d)) {
3772 for (i = 0; i < count; i++)
3773 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3774 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3777 if (!This->isRecordingState)
3779 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3783 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3784 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3786 return WINED3D_OK;
3789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3790 IWineD3DDevice *iface,
3791 UINT start,
3792 float *dstData,
3793 UINT count) {
3795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3796 int cnt = min(count, This->d3d_pshader_constantF - start);
3798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3799 iface, dstData, start, count);
3801 if (!dstData || cnt < 0)
3802 return WINED3DERR_INVALIDCALL;
3804 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3805 return WINED3D_OK;
3808 /* Context activation is done by the caller. */
3809 /* Do not call while under the GL lock. */
3810 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3811 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3812 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3813 DWORD DestFVF)
3815 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3816 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3817 unsigned int i;
3818 WINED3DVIEWPORT vp;
3819 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3820 BOOL doClip;
3821 DWORD numTextures;
3823 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3825 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3828 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3830 ERR("Source has no position mask\n");
3831 return WINED3DERR_INVALIDCALL;
3834 if (!dest->resource.allocatedMemory)
3835 buffer_get_sysmem(dest, gl_info);
3837 /* Get a pointer into the destination vbo(create one if none exists) and
3838 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3840 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3842 dest->flags |= WINED3D_BUFFER_CREATEBO;
3843 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3846 if (dest->buffer_object)
3848 unsigned char extrabytes = 0;
3849 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3850 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3851 * this may write 4 extra bytes beyond the area that should be written
3853 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3854 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3855 if(!dest_conv_addr) {
3856 ERR("Out of memory\n");
3857 /* Continue without storing converted vertices */
3859 dest_conv = dest_conv_addr;
3862 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3864 static BOOL warned = FALSE;
3866 * The clipping code is not quite correct. Some things need
3867 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3868 * so disable clipping for now.
3869 * (The graphics in Half-Life are broken, and my processvertices
3870 * test crashes with IDirect3DDevice3)
3871 doClip = TRUE;
3873 doClip = FALSE;
3874 if(!warned) {
3875 warned = TRUE;
3876 FIXME("Clipping is broken and disabled for now\n");
3878 } else doClip = FALSE;
3879 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3881 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3882 WINED3DTS_VIEW,
3883 &view_mat);
3884 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3885 WINED3DTS_PROJECTION,
3886 &proj_mat);
3887 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3888 WINED3DTS_WORLDMATRIX(0),
3889 &world_mat);
3891 TRACE("View mat:\n");
3892 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);
3893 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);
3894 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);
3895 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);
3897 TRACE("Proj mat:\n");
3898 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);
3899 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);
3900 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);
3901 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);
3903 TRACE("World mat:\n");
3904 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);
3905 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);
3906 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);
3907 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);
3909 /* Get the viewport */
3910 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3911 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3912 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3914 multiply_matrix(&mat,&view_mat,&world_mat);
3915 multiply_matrix(&mat,&proj_mat,&mat);
3917 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3919 for (i = 0; i < dwCount; i+= 1) {
3920 unsigned int tex_index;
3922 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3923 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3924 /* The position first */
3925 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3926 const float *p = (const float *)(element->data + i * element->stride);
3927 float x, y, z, rhw;
3928 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3930 /* Multiplication with world, view and projection matrix */
3931 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);
3932 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);
3933 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);
3934 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);
3936 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3938 /* WARNING: The following things are taken from d3d7 and were not yet checked
3939 * against d3d8 or d3d9!
3942 /* Clipping conditions: From msdn
3944 * A vertex is clipped if it does not match the following requirements
3945 * -rhw < x <= rhw
3946 * -rhw < y <= rhw
3947 * 0 < z <= rhw
3948 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3950 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3951 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3955 if( !doClip ||
3956 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3957 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3958 ( rhw > eps ) ) ) {
3960 /* "Normal" viewport transformation (not clipped)
3961 * 1) The values are divided by rhw
3962 * 2) The y axis is negative, so multiply it with -1
3963 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3964 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3965 * 4) Multiply x with Width/2 and add Width/2
3966 * 5) The same for the height
3967 * 6) Add the viewpoint X and Y to the 2D coordinates and
3968 * The minimum Z value to z
3969 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3971 * Well, basically it's simply a linear transformation into viewport
3972 * coordinates
3975 x /= rhw;
3976 y /= rhw;
3977 z /= rhw;
3979 y *= -1;
3981 x *= vp.Width / 2;
3982 y *= vp.Height / 2;
3983 z *= vp.MaxZ - vp.MinZ;
3985 x += vp.Width / 2 + vp.X;
3986 y += vp.Height / 2 + vp.Y;
3987 z += vp.MinZ;
3989 rhw = 1 / rhw;
3990 } else {
3991 /* That vertex got clipped
3992 * Contrary to OpenGL it is not dropped completely, it just
3993 * undergoes a different calculation.
3995 TRACE("Vertex got clipped\n");
3996 x += rhw;
3997 y += rhw;
3999 x /= 2;
4000 y /= 2;
4002 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4003 * outside of the main vertex buffer memory. That needs some more
4004 * investigation...
4008 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4011 ( (float *) dest_ptr)[0] = x;
4012 ( (float *) dest_ptr)[1] = y;
4013 ( (float *) dest_ptr)[2] = z;
4014 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4016 dest_ptr += 3 * sizeof(float);
4018 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4019 dest_ptr += sizeof(float);
4022 if(dest_conv) {
4023 float w = 1 / rhw;
4024 ( (float *) dest_conv)[0] = x * w;
4025 ( (float *) dest_conv)[1] = y * w;
4026 ( (float *) dest_conv)[2] = z * w;
4027 ( (float *) dest_conv)[3] = w;
4029 dest_conv += 3 * sizeof(float);
4031 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4032 dest_conv += sizeof(float);
4036 if (DestFVF & WINED3DFVF_PSIZE) {
4037 dest_ptr += sizeof(DWORD);
4038 if(dest_conv) dest_conv += sizeof(DWORD);
4040 if (DestFVF & WINED3DFVF_NORMAL) {
4041 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4042 const float *normal = (const float *)(element->data + i * element->stride);
4043 /* AFAIK this should go into the lighting information */
4044 FIXME("Didn't expect the destination to have a normal\n");
4045 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4046 if(dest_conv) {
4047 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4051 if (DestFVF & WINED3DFVF_DIFFUSE) {
4052 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4053 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4054 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4056 static BOOL warned = FALSE;
4058 if(!warned) {
4059 ERR("No diffuse color in source, but destination has one\n");
4060 warned = TRUE;
4063 *( (DWORD *) dest_ptr) = 0xffffffff;
4064 dest_ptr += sizeof(DWORD);
4066 if(dest_conv) {
4067 *( (DWORD *) dest_conv) = 0xffffffff;
4068 dest_conv += sizeof(DWORD);
4071 else {
4072 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4073 if(dest_conv) {
4074 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4075 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4076 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4077 dest_conv += sizeof(DWORD);
4082 if (DestFVF & WINED3DFVF_SPECULAR)
4084 /* What's the color value in the feedback buffer? */
4085 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4086 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4087 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4089 static BOOL warned = FALSE;
4091 if(!warned) {
4092 ERR("No specular color in source, but destination has one\n");
4093 warned = TRUE;
4096 *( (DWORD *) dest_ptr) = 0xFF000000;
4097 dest_ptr += sizeof(DWORD);
4099 if(dest_conv) {
4100 *( (DWORD *) dest_conv) = 0xFF000000;
4101 dest_conv += sizeof(DWORD);
4104 else {
4105 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4106 if(dest_conv) {
4107 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4108 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4109 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4110 dest_conv += sizeof(DWORD);
4115 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4116 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4117 const float *tex_coord = (const float *)(element->data + i * element->stride);
4118 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4120 ERR("No source texture, but destination requests one\n");
4121 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4122 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4124 else {
4125 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4126 if(dest_conv) {
4127 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4133 if (dest_conv)
4135 ENTER_GL();
4137 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4138 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4139 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4140 dwCount * get_flexible_vertex_size(DestFVF),
4141 dest_conv_addr));
4142 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4144 LEAVE_GL();
4146 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4149 return WINED3D_OK;
4151 #undef copy_and_next
4153 /* Do not call while under the GL lock. */
4154 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4155 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4156 DWORD DestFVF)
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 struct wined3d_stream_info stream_info;
4160 const struct wined3d_gl_info *gl_info;
4161 struct wined3d_context *context;
4162 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4163 HRESULT hr;
4165 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4167 if(pVertexDecl) {
4168 ERR("Output vertex declaration not implemented yet\n");
4171 /* Need any context to write to the vbo. */
4172 context = context_acquire(This, NULL);
4173 gl_info = context->gl_info;
4175 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4176 * control the streamIsUP flag, thus restore it afterwards.
4178 This->stateBlock->state.user_stream = FALSE;
4179 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4180 This->stateBlock->state.user_stream = streamWasUP;
4182 if(vbo || SrcStartIndex) {
4183 unsigned int i;
4184 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4185 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4187 * Also get the start index in, but only loop over all elements if there's something to add at all.
4189 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4191 struct wined3d_stream_info_element *e;
4193 if (!(stream_info.use_map & (1 << i))) continue;
4195 e = &stream_info.elements[i];
4196 if (e->buffer_object)
4198 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4199 e->buffer_object = 0;
4200 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4201 ENTER_GL();
4202 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4203 vb->buffer_object = 0;
4204 LEAVE_GL();
4206 if (e->data) e->data += e->stride * SrcStartIndex;
4210 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4211 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4213 context_release(context);
4215 return hr;
4218 /*****
4219 * Get / Set Texture Stage States
4220 * TODO: Verify against dx9 definitions
4221 *****/
4222 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4225 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4226 DWORD oldValue;
4228 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4230 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4232 WARN("Invalid Type %d passed.\n", Type);
4233 return WINED3D_OK;
4236 if (Stage >= gl_info->limits.texture_stages)
4238 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4239 Stage, gl_info->limits.texture_stages - 1);
4240 return WINED3D_OK;
4243 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4244 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4245 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4247 if (This->isRecordingState) {
4248 TRACE("Recording... not performing anything\n");
4249 return WINED3D_OK;
4252 /* Checked after the assignments to allow proper stateblock recording */
4253 if(oldValue == Value) {
4254 TRACE("App is setting the old value over, nothing to do\n");
4255 return WINED3D_OK;
4258 if (Stage > This->stateBlock->state.lowest_disabled_stage
4259 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4260 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4262 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4263 * Changes in other states are important on disabled stages too
4265 return WINED3D_OK;
4268 if(Type == WINED3DTSS_COLOROP) {
4269 unsigned int i;
4271 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4272 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4273 * they have to be disabled
4275 * The current stage is dirtified below.
4277 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4279 TRACE("Additionally dirtifying stage %u\n", i);
4280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4282 This->stateBlock->state.lowest_disabled_stage = Stage;
4283 TRACE("New lowest disabled: %u\n", Stage);
4284 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4285 /* Previously disabled stage enabled. Stages above it may need enabling
4286 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4287 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4289 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4292 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4294 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4295 break;
4296 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4299 This->stateBlock->state.lowest_disabled_stage = i;
4300 TRACE("New lowest disabled: %u\n", i);
4304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4306 return WINED3D_OK;
4309 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4313 TRACE("iface %p, stage %u, state %s, value %p.\n",
4314 iface, Stage, debug_d3dtexturestate(Type), pValue);
4316 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4318 WARN("Invalid Type %d passed.\n", Type);
4319 return WINED3D_OK;
4322 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4323 TRACE("Returning %#x.\n", *pValue);
4325 return WINED3D_OK;
4328 /*****
4329 * Get / Set Texture
4330 *****/
4331 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4332 DWORD stage, IWineD3DBaseTexture *texture)
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4336 IWineD3DBaseTexture *prev;
4338 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4340 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4341 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4343 /* Windows accepts overflowing this array... we do not. */
4344 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4346 WARN("Ignoring invalid stage %u.\n", stage);
4347 return WINED3D_OK;
4350 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4351 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4353 WARN("Rejecting attempt to set scratch texture.\n");
4354 return WINED3DERR_INVALIDCALL;
4357 This->updateStateBlock->changed.textures |= 1 << stage;
4359 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4360 TRACE("Previous texture %p.\n", prev);
4362 if (texture == prev)
4364 TRACE("App is setting the same texture again, nothing to do.\n");
4365 return WINED3D_OK;
4368 TRACE("Setting new texture to %p.\n", texture);
4369 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4371 if (This->isRecordingState)
4373 TRACE("Recording... not performing anything\n");
4375 if (texture) IWineD3DBaseTexture_AddRef(texture);
4376 if (prev) IWineD3DBaseTexture_Release(prev);
4378 return WINED3D_OK;
4381 if (texture)
4383 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4384 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4385 GLenum dimensions = t->baseTexture.target;
4387 IWineD3DBaseTexture_AddRef(texture);
4389 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4392 if (!prev && stage < gl_info->limits.texture_stages)
4394 /* The source arguments for color and alpha ops have different
4395 * meanings when a NULL texture is bound, so the COLOROP and
4396 * ALPHAOP have to be dirtified. */
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4401 if (bind_count == 1) t->baseTexture.sampler = stage;
4404 if (prev)
4406 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4407 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4409 IWineD3DBaseTexture_Release(prev);
4411 if (!texture && stage < gl_info->limits.texture_stages)
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4417 if (bind_count && t->baseTexture.sampler == stage)
4419 unsigned int i;
4421 /* Search for other stages the texture is bound to. Shouldn't
4422 * happen if applications bind textures to a single stage only. */
4423 TRACE("Searching for other stages the texture is bound to.\n");
4424 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4426 if (This->updateStateBlock->state.textures[i] == t)
4428 TRACE("Texture is also bound to stage %u.\n", i);
4429 t->baseTexture.sampler = i;
4430 break;
4436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4438 return WINED3D_OK;
4441 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4446 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4447 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4450 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4452 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4453 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4456 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4457 if (*ppTexture)
4458 IWineD3DBaseTexture_AddRef(*ppTexture);
4460 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4462 return WINED3D_OK;
4465 /*****
4466 * Get Back Buffer
4467 *****/
4468 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4469 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4471 IWineD3DSwapChain *swapchain;
4472 HRESULT hr;
4474 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4475 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4477 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4478 if (FAILED(hr))
4480 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4481 return hr;
4484 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4485 IWineD3DSwapChain_Release(swapchain);
4486 if (FAILED(hr))
4488 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4489 return hr;
4492 return WINED3D_OK;
4495 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 WARN("(%p) : stub, calling idirect3d for now\n", This);
4498 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4501 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DSwapChain *swapChain;
4504 HRESULT hr;
4506 if(iSwapChain > 0) {
4507 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4508 if (hr == WINED3D_OK) {
4509 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4510 IWineD3DSwapChain_Release(swapChain);
4511 } else {
4512 FIXME("(%p) Error getting display mode\n", This);
4514 } else {
4515 /* Don't read the real display mode,
4516 but return the stored mode instead. X11 can't change the color
4517 depth, and some apps are pretty angry if they SetDisplayMode from
4518 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4520 Also don't relay to the swapchain because with ddraw it's possible
4521 that there isn't a swapchain at all */
4522 pMode->Width = This->ddraw_width;
4523 pMode->Height = This->ddraw_height;
4524 pMode->Format = This->ddraw_format;
4525 pMode->RefreshRate = 0;
4526 hr = WINED3D_OK;
4529 return hr;
4532 /*****
4533 * Stateblock related functions
4534 *****/
4536 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 IWineD3DStateBlock *stateblock;
4539 HRESULT hr;
4541 TRACE("(%p)\n", This);
4543 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4545 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4546 if (FAILED(hr)) return hr;
4548 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4549 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4550 This->isRecordingState = TRUE;
4552 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4561 if (!This->isRecordingState) {
4562 WARN("(%p) not recording! returning error\n", This);
4563 *ppStateBlock = NULL;
4564 return WINED3DERR_INVALIDCALL;
4567 stateblock_init_contained_states(object);
4569 *ppStateBlock = (IWineD3DStateBlock*) object;
4570 This->isRecordingState = FALSE;
4571 This->updateStateBlock = This->stateBlock;
4572 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4573 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4574 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4575 return WINED3D_OK;
4578 /*****
4579 * Scene related functions
4580 *****/
4581 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4582 /* At the moment we have no need for any functionality at the beginning
4583 of a scene */
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 TRACE("(%p)\n", This);
4587 if(This->inScene) {
4588 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4589 return WINED3DERR_INVALIDCALL;
4591 This->inScene = TRUE;
4592 return WINED3D_OK;
4595 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 struct wined3d_context *context;
4600 TRACE("(%p)\n", This);
4602 if(!This->inScene) {
4603 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4604 return WINED3DERR_INVALIDCALL;
4607 context = context_acquire(This, NULL);
4608 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4609 wglFlush();
4610 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4611 * fails. */
4612 context_release(context);
4614 This->inScene = FALSE;
4615 return WINED3D_OK;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4619 const RECT *pSourceRect, const RECT *pDestRect,
4620 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4622 IWineD3DSwapChain *swapChain = NULL;
4623 int i;
4624 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4626 TRACE("iface %p.\n", iface);
4628 for(i = 0 ; i < swapchains ; i ++) {
4630 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4631 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4632 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4633 IWineD3DSwapChain_Release(swapChain);
4636 return WINED3D_OK;
4639 /* Do not call while under the GL lock. */
4640 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4641 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4643 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4644 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4645 RECT draw_rect;
4647 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4648 iface, rect_count, rects, flags, color, depth, stencil);
4650 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4652 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4653 /* TODO: What about depth stencil buffers without stencil bits? */
4654 return WINED3DERR_INVALIDCALL;
4657 device_get_draw_rect(device, &draw_rect);
4659 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4660 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4663 /*****
4664 * Drawing functions
4665 *****/
4667 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4668 WINED3DPRIMITIVETYPE primitive_type)
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4674 This->updateStateBlock->changed.primitive_type = TRUE;
4675 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4678 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4679 WINED3DPRIMITIVETYPE *primitive_type)
4681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4685 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4687 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4690 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4694 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4696 if (!This->stateBlock->state.vertex_declaration)
4698 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4699 return WINED3DERR_INVALIDCALL;
4702 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4703 if (This->stateBlock->state.user_stream)
4705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4706 This->stateBlock->state.user_stream = FALSE;
4709 if (This->stateBlock->state.load_base_vertex_index)
4711 This->stateBlock->state.load_base_vertex_index = 0;
4712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4714 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4715 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4716 return WINED3D_OK;
4719 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 struct wined3d_buffer *index_buffer;
4723 UINT idxStride = 2;
4724 GLuint vbo;
4726 index_buffer = This->stateBlock->state.index_buffer;
4727 if (!index_buffer)
4729 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4730 * without an index buffer set. (The first time at least...)
4731 * D3D8 simply dies, but I doubt it can do much harm to return
4732 * D3DERR_INVALIDCALL there as well. */
4733 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4734 return WINED3DERR_INVALIDCALL;
4737 if (!This->stateBlock->state.vertex_declaration)
4739 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4740 return WINED3DERR_INVALIDCALL;
4743 if (This->stateBlock->state.user_stream)
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4746 This->stateBlock->state.user_stream = FALSE;
4748 vbo = index_buffer->buffer_object;
4750 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4752 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4753 idxStride = 2;
4754 else
4755 idxStride = 4;
4757 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4759 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4763 drawPrimitive(iface, index_count, startIndex, idxStride,
4764 vbo ? NULL : index_buffer->resource.allocatedMemory);
4766 return WINED3D_OK;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4770 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4773 struct wined3d_stream_state *stream;
4774 IWineD3DBuffer *vb;
4776 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4777 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4779 if (!This->stateBlock->state.vertex_declaration)
4781 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4786 stream = &This->stateBlock->state.streams[0];
4787 vb = (IWineD3DBuffer *)stream->buffer;
4788 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4789 if (vb) IWineD3DBuffer_Release(vb);
4790 stream->offset = 0;
4791 stream->stride = VertexStreamZeroStride;
4792 This->stateBlock->state.user_stream = TRUE;
4793 This->stateBlock->state.load_base_vertex_index = 0;
4795 /* TODO: Only mark dirty if drawing from a different UP address */
4796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4798 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4800 /* MSDN specifies stream zero settings must be set to NULL */
4801 stream->buffer = NULL;
4802 stream->stride = 0;
4804 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4805 * the new stream sources or use UP drawing again
4807 return WINED3D_OK;
4810 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4811 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4812 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4814 int idxStride;
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 struct wined3d_stream_state *stream;
4817 IWineD3DBuffer *vb;
4818 IWineD3DBuffer *ib;
4820 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4821 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4823 if (!This->stateBlock->state.vertex_declaration)
4825 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4826 return WINED3DERR_INVALIDCALL;
4829 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4830 idxStride = 2;
4831 } else {
4832 idxStride = 4;
4835 stream = &This->stateBlock->state.streams[0];
4836 vb = (IWineD3DBuffer *)stream->buffer;
4837 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4838 if (vb) IWineD3DBuffer_Release(vb);
4839 stream->offset = 0;
4840 stream->stride = VertexStreamZeroStride;
4841 This->stateBlock->state.user_stream = TRUE;
4843 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4844 This->stateBlock->state.base_vertex_index = 0;
4845 This->stateBlock->state.load_base_vertex_index = 0;
4846 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4850 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4852 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4853 stream->buffer = NULL;
4854 stream->stride = 0;
4855 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4856 if (ib)
4858 IWineD3DBuffer_Release(ib);
4859 This->stateBlock->state.index_buffer = NULL;
4861 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4862 * SetStreamSource to specify a vertex buffer
4865 return WINED3D_OK;
4868 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4869 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4873 /* Mark the state dirty until we have nicer tracking
4874 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4875 * that value.
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4879 This->stateBlock->state.base_vertex_index = 0;
4880 This->up_strided = DrawPrimStrideData;
4881 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4882 This->up_strided = NULL;
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4887 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4888 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4891 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4893 /* Mark the state dirty until we have nicer tracking
4894 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4895 * that value.
4897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4899 This->stateBlock->state.user_stream = TRUE;
4900 This->stateBlock->state.base_vertex_index = 0;
4901 This->up_strided = DrawPrimStrideData;
4902 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4903 This->up_strided = NULL;
4904 return WINED3D_OK;
4907 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4908 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4909 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4911 WINED3DLOCKED_BOX src;
4912 WINED3DLOCKED_BOX dst;
4913 HRESULT hr;
4915 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4916 iface, pSourceVolume, pDestinationVolume);
4918 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4919 * dirtification to improve loading performance.
4921 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4922 if (FAILED(hr)) return hr;
4923 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4924 if (FAILED(hr))
4926 IWineD3DVolume_Unmap(pSourceVolume);
4927 return hr;
4930 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4932 hr = IWineD3DVolume_Unmap(pDestinationVolume);
4933 if (FAILED(hr))
4934 IWineD3DVolume_Unmap(pSourceVolume);
4935 else
4936 hr = IWineD3DVolume_Unmap(pSourceVolume);
4938 return hr;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4942 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4944 unsigned int level_count, i;
4945 WINED3DRESOURCETYPE type;
4946 HRESULT hr;
4948 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4950 /* Verify that the source and destination textures are non-NULL. */
4951 if (!src_texture || !dst_texture)
4953 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4954 return WINED3DERR_INVALIDCALL;
4957 if (src_texture == dst_texture)
4959 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4960 return WINED3DERR_INVALIDCALL;
4963 /* Verify that the source and destination textures are the same type. */
4964 type = IWineD3DBaseTexture_GetType(src_texture);
4965 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4967 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4968 return WINED3DERR_INVALIDCALL;
4971 /* Check that both textures have the identical numbers of levels. */
4972 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4973 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4975 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4976 return WINED3DERR_INVALIDCALL;
4979 /* Make sure that the destination texture is loaded. */
4980 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4982 /* Update every surface level of the texture. */
4983 switch (type)
4985 case WINED3DRTYPE_TEXTURE:
4987 IWineD3DSurface *src_surface;
4988 IWineD3DSurface *dst_surface;
4990 for (i = 0; i < level_count; ++i)
4992 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4993 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4994 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4995 IWineD3DSurface_Release(dst_surface);
4996 IWineD3DSurface_Release(src_surface);
4997 if (FAILED(hr))
4999 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5000 return hr;
5003 break;
5006 case WINED3DRTYPE_CUBETEXTURE:
5008 IWineD3DSurface *src_surface;
5009 IWineD3DSurface *dst_surface;
5011 for (i = 0; i < level_count * 6; ++i)
5013 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5014 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5015 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5016 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5017 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5018 IWineD3DSurface_Release(dst_surface);
5019 IWineD3DSurface_Release(src_surface);
5020 if (FAILED(hr))
5022 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5023 return hr;
5026 break;
5029 case WINED3DRTYPE_VOLUMETEXTURE:
5031 IWineD3DVolume *src_volume;
5032 IWineD3DVolume *dst_volume;
5034 for (i = 0; i < level_count; ++i)
5036 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5037 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5038 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5039 IWineD3DVolume_Release(dst_volume);
5040 IWineD3DVolume_Release(src_volume);
5041 if (FAILED(hr))
5043 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5044 return hr;
5047 break;
5050 default:
5051 FIXME("Unsupported texture type %#x.\n", type);
5052 return WINED3DERR_INVALIDCALL;
5055 return WINED3D_OK;
5058 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5059 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5061 IWineD3DSwapChain *swapchain;
5062 HRESULT hr;
5064 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5066 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5067 if (FAILED(hr)) return hr;
5069 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5070 IWineD3DSwapChain_Release(swapchain);
5072 return hr;
5075 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5077 IWineD3DBaseTextureImpl *texture;
5078 DWORD i;
5080 TRACE("(%p) : %p\n", This, pNumPasses);
5082 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5084 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5086 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5087 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5089 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5091 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5092 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5095 texture = This->stateBlock->state.textures[i];
5096 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5098 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5100 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5101 return E_FAIL;
5103 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5105 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5106 return E_FAIL;
5108 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5109 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5111 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5112 return E_FAIL;
5116 /* return a sensible default */
5117 *pNumPasses = 1;
5119 TRACE("returning D3D_OK\n");
5120 return WINED3D_OK;
5123 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5125 int i;
5127 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5129 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5130 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5131 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5133 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5138 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5140 int j;
5141 UINT NewSize;
5142 PALETTEENTRY **palettes;
5144 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5146 if (PaletteNumber >= MAX_PALETTES) {
5147 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5148 return WINED3DERR_INVALIDCALL;
5151 if (PaletteNumber >= This->NumberOfPalettes) {
5152 NewSize = This->NumberOfPalettes;
5153 do {
5154 NewSize *= 2;
5155 } while(PaletteNumber >= NewSize);
5156 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5157 if (!palettes) {
5158 ERR("Out of memory!\n");
5159 return E_OUTOFMEMORY;
5161 This->palettes = palettes;
5162 This->NumberOfPalettes = NewSize;
5165 if (!This->palettes[PaletteNumber]) {
5166 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5167 if (!This->palettes[PaletteNumber]) {
5168 ERR("Out of memory!\n");
5169 return E_OUTOFMEMORY;
5173 for (j = 0; j < 256; ++j) {
5174 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5175 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5176 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5177 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5179 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5180 TRACE("(%p) : returning\n", This);
5181 return WINED3D_OK;
5184 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5186 int j;
5187 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5188 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5189 /* What happens in such situation isn't documented; Native seems to silently abort
5190 on such conditions. Return Invalid Call. */
5191 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5192 return WINED3DERR_INVALIDCALL;
5194 for (j = 0; j < 256; ++j) {
5195 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5196 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5197 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5198 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5200 TRACE("(%p) : returning\n", This);
5201 return WINED3D_OK;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5207 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5208 (tested with reference rasterizer). Return Invalid Call. */
5209 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5210 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5211 return WINED3DERR_INVALIDCALL;
5213 /*TODO: stateblocks */
5214 if (This->currentPalette != PaletteNumber) {
5215 This->currentPalette = PaletteNumber;
5216 dirtify_p8_texture_samplers(This);
5218 TRACE("(%p) : returning\n", This);
5219 return WINED3D_OK;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 if (!PaletteNumber)
5227 WARN("(%p) : returning Invalid Call\n", This);
5228 return WINED3DERR_INVALIDCALL;
5230 /*TODO: stateblocks */
5231 *PaletteNumber = This->currentPalette;
5232 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5233 return WINED3D_OK;
5236 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 static BOOL warned;
5239 if (!warned)
5241 FIXME("(%p) : stub\n", This);
5242 warned = TRUE;
5245 This->softwareVertexProcessing = bSoftware;
5246 return WINED3D_OK;
5250 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5252 static BOOL warned;
5253 if (!warned)
5255 FIXME("(%p) : stub\n", This);
5256 warned = TRUE;
5258 return This->softwareVertexProcessing;
5261 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5262 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5264 IWineD3DSwapChain *swapchain;
5265 HRESULT hr;
5267 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5268 iface, swapchain_idx, raster_status);
5270 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5271 if (FAILED(hr))
5273 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5274 return hr;
5277 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5278 IWineD3DSwapChain_Release(swapchain);
5279 if (FAILED(hr))
5281 WARN("Failed to get raster status, hr %#x.\n", hr);
5282 return hr;
5285 return WINED3D_OK;
5288 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5290 static BOOL warned;
5291 if(nSegments != 0.0f) {
5292 if (!warned)
5294 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5295 warned = TRUE;
5298 return WINED3D_OK;
5301 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5303 static BOOL warned;
5304 if (!warned)
5306 FIXME("iface %p stub!\n", iface);
5307 warned = TRUE;
5309 return 0.0f;
5312 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5313 IWineD3DSurface *src_surface, const RECT *src_rect,
5314 IWineD3DSurface *dst_surface, const POINT *dst_point)
5316 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5317 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5319 const struct wined3d_format *src_format;
5320 const struct wined3d_format *dst_format;
5321 const struct wined3d_gl_info *gl_info;
5322 struct wined3d_context *context;
5323 const unsigned char *data;
5324 UINT update_w, update_h;
5325 CONVERT_TYPES convert;
5326 UINT src_w, src_h;
5327 UINT dst_x, dst_y;
5328 DWORD sampler;
5329 struct wined3d_format format;
5331 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5332 iface, src_surface, wine_dbgstr_rect(src_rect),
5333 dst_surface, wine_dbgstr_point(dst_point));
5335 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5337 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5338 src_surface, dst_surface);
5339 return WINED3DERR_INVALIDCALL;
5342 src_format = src_impl->resource.format;
5343 dst_format = dst_impl->resource.format;
5345 if (src_format->id != dst_format->id)
5347 WARN("Source and destination surfaces should have the same format.\n");
5348 return WINED3DERR_INVALIDCALL;
5351 dst_x = dst_point ? dst_point->x : 0;
5352 dst_y = dst_point ? dst_point->y : 0;
5354 /* This call loads the OpenGL surface directly, instead of copying the
5355 * surface to the destination's sysmem copy. If surface conversion is
5356 * needed, use BltFast instead to copy in sysmem and use regular surface
5357 * loading. */
5358 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5359 if (convert != NO_CONVERSION || format.convert)
5360 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5362 context = context_acquire(This, NULL);
5363 gl_info = context->gl_info;
5365 ENTER_GL();
5366 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5367 checkGLcall("glActiveTextureARB");
5368 LEAVE_GL();
5370 /* Make sure the surface is loaded and up to date */
5371 surface_internal_preload(dst_impl, SRGB_RGB);
5372 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5374 src_w = src_impl->currentDesc.Width;
5375 src_h = src_impl->currentDesc.Height;
5376 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5377 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5379 data = IWineD3DSurface_GetData(src_surface);
5380 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5382 ENTER_GL();
5384 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5386 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5387 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5388 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5390 if (src_rect)
5392 data += (src_rect->top / src_format->block_height) * src_pitch;
5393 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5396 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5397 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5398 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5400 if (row_length == src_pitch)
5402 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5403 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5405 else
5407 UINT row, y;
5409 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5410 * can't use the unpack row length like below. */
5411 for (row = 0, y = dst_y; row < row_count; ++row)
5413 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5414 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5415 y += src_format->block_height;
5416 data += src_pitch;
5419 checkGLcall("glCompressedTexSubImage2DARB");
5421 else
5423 if (src_rect)
5425 data += src_rect->top * src_w * src_format->byte_count;
5426 data += src_rect->left * src_format->byte_count;
5429 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5430 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5431 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5433 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5434 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5435 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5436 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5437 checkGLcall("glTexSubImage2D");
5440 LEAVE_GL();
5441 context_release(context);
5443 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5444 sampler = This->rev_tex_unit_map[0];
5445 if (sampler != WINED3D_UNMAPPED_STAGE)
5447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5450 return WINED3D_OK;
5453 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 struct WineD3DRectPatch *patch;
5456 GLenum old_primitive_type;
5457 unsigned int i;
5458 struct list *e;
5459 BOOL found;
5460 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5462 if(!(Handle || pRectPatchInfo)) {
5463 /* TODO: Write a test for the return value, thus the FIXME */
5464 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5465 return WINED3DERR_INVALIDCALL;
5468 if(Handle) {
5469 i = PATCHMAP_HASHFUNC(Handle);
5470 found = FALSE;
5471 LIST_FOR_EACH(e, &This->patches[i]) {
5472 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5473 if(patch->Handle == Handle) {
5474 found = TRUE;
5475 break;
5479 if(!found) {
5480 TRACE("Patch does not exist. Creating a new one\n");
5481 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5482 patch->Handle = Handle;
5483 list_add_head(&This->patches[i], &patch->entry);
5484 } else {
5485 TRACE("Found existing patch %p\n", patch);
5487 } else {
5488 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5489 * attributes we have to tesselate, read back, and draw. This needs a patch
5490 * management structure instance. Create one.
5492 * A possible improvement is to check if a vertex shader is used, and if not directly
5493 * draw the patch.
5495 FIXME("Drawing an uncached patch. This is slow\n");
5496 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5499 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5500 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5501 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5503 HRESULT hr;
5504 TRACE("Tesselation density or patch info changed, retesselating\n");
5506 if(pRectPatchInfo) {
5507 patch->RectPatchInfo = *pRectPatchInfo;
5509 patch->numSegs[0] = pNumSegs[0];
5510 patch->numSegs[1] = pNumSegs[1];
5511 patch->numSegs[2] = pNumSegs[2];
5512 patch->numSegs[3] = pNumSegs[3];
5514 hr = tesselate_rectpatch(This, patch);
5515 if(FAILED(hr)) {
5516 WARN("Patch tesselation failed\n");
5518 /* Do not release the handle to store the params of the patch */
5519 if(!Handle) {
5520 HeapFree(GetProcessHeap(), 0, patch);
5522 return hr;
5526 This->currentPatch = patch;
5527 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5528 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5529 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5530 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5531 This->currentPatch = NULL;
5533 /* Destroy uncached patches */
5534 if(!Handle) {
5535 HeapFree(GetProcessHeap(), 0, patch->mem);
5536 HeapFree(GetProcessHeap(), 0, patch);
5538 return WINED3D_OK;
5541 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5542 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5544 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5545 iface, handle, segment_count, patch_info);
5547 return WINED3D_OK;
5550 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5552 int i;
5553 struct WineD3DRectPatch *patch;
5554 struct list *e;
5555 TRACE("(%p) Handle(%d)\n", This, Handle);
5557 i = PATCHMAP_HASHFUNC(Handle);
5558 LIST_FOR_EACH(e, &This->patches[i]) {
5559 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5560 if(patch->Handle == Handle) {
5561 TRACE("Deleting patch %p\n", patch);
5562 list_remove(&patch->entry);
5563 HeapFree(GetProcessHeap(), 0, patch->mem);
5564 HeapFree(GetProcessHeap(), 0, patch);
5565 return WINED3D_OK;
5569 /* TODO: Write a test for the return value */
5570 FIXME("Attempt to destroy nonexistent patch\n");
5571 return WINED3DERR_INVALIDCALL;
5574 /* Do not call while under the GL lock. */
5575 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5576 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5578 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5580 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5581 iface, surface, wine_dbgstr_rect(rect),
5582 color->r, color->g, color->b, color->a);
5584 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5586 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5587 return WINED3DERR_INVALIDCALL;
5590 return surface_color_fill(s, rect, color);
5593 /* Do not call while under the GL lock. */
5594 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5595 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5597 IWineD3DResource *resource;
5598 HRESULT hr;
5600 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5601 if (FAILED(hr))
5603 ERR("Failed to get resource, hr %#x\n", hr);
5604 return;
5607 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5609 FIXME("Only supported on surface resources\n");
5610 IWineD3DResource_Release(resource);
5611 return;
5614 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5615 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5617 IWineD3DResource_Release(resource);
5620 /* rendertarget and depth stencil functions */
5621 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5622 DWORD render_target_idx, IWineD3DSurface **render_target)
5624 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5626 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5627 iface, render_target_idx, render_target);
5629 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5631 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5632 return WINED3DERR_INVALIDCALL;
5635 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5636 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5638 TRACE("Returning render target %p.\n", *render_target);
5640 return WINED3D_OK;
5643 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5645 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5647 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5649 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5650 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5651 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5652 IWineD3DSurface_AddRef(*depth_stencil);
5654 return WINED3D_OK;
5657 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5658 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5660 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5661 IWineD3DSurfaceImpl *prev;
5663 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5664 iface, render_target_idx, render_target, set_viewport);
5666 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5668 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5669 return WINED3DERR_INVALIDCALL;
5672 prev = device->render_targets[render_target_idx];
5673 if (render_target == (IWineD3DSurface *)prev)
5675 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5676 return WINED3D_OK;
5679 /* Render target 0 can't be set to NULL. */
5680 if (!render_target && !render_target_idx)
5682 WARN("Trying to set render target 0 to NULL.\n");
5683 return WINED3DERR_INVALIDCALL;
5686 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5688 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5689 return WINED3DERR_INVALIDCALL;
5692 if (render_target) IWineD3DSurface_AddRef(render_target);
5693 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5694 /* Release after the assignment, to prevent device_resource_released()
5695 * from seeing the surface as still in use. */
5696 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5698 /* Render target 0 is special. */
5699 if (!render_target_idx && set_viewport)
5701 /* Set the viewport and scissor rectangles, if requested. Tests show
5702 * that stateblock recording is ignored, the change goes directly
5703 * into the primary stateblock. */
5704 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5705 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5706 device->stateBlock->state.viewport.X = 0;
5707 device->stateBlock->state.viewport.Y = 0;
5708 device->stateBlock->state.viewport.MaxZ = 1.0f;
5709 device->stateBlock->state.viewport.MinZ = 0.0f;
5710 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5712 device->stateBlock->state.scissor_rect.top = 0;
5713 device->stateBlock->state.scissor_rect.left = 0;
5714 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5715 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5716 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5719 return WINED3D_OK;
5722 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 IWineD3DSurfaceImpl *tmp;
5727 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5729 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5731 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5732 return WINED3D_OK;
5735 if (This->depth_stencil)
5737 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5738 || This->depth_stencil->Flags & SFLAG_DISCARD)
5740 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5741 This->depth_stencil->currentDesc.Width,
5742 This->depth_stencil->currentDesc.Height);
5743 if (This->depth_stencil == This->onscreen_depth_stencil)
5745 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5746 This->onscreen_depth_stencil = NULL;
5751 tmp = This->depth_stencil;
5752 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5753 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5754 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5756 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5758 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5759 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5764 return WINED3D_OK;
5767 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5768 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5771 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5772 WINED3DLOCKED_RECT lockedRect;
5774 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5775 iface, XHotSpot, YHotSpot, cursor_image);
5777 /* some basic validation checks */
5778 if (This->cursorTexture)
5780 struct wined3d_context *context = context_acquire(This, NULL);
5781 ENTER_GL();
5782 glDeleteTextures(1, &This->cursorTexture);
5783 LEAVE_GL();
5784 context_release(context);
5785 This->cursorTexture = 0;
5788 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5789 This->haveHardwareCursor = TRUE;
5790 else
5791 This->haveHardwareCursor = FALSE;
5793 if (cursor_image)
5795 WINED3DLOCKED_RECT rect;
5797 /* MSDN: Cursor must be A8R8G8B8 */
5798 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5800 WARN("surface %p has an invalid format.\n", cursor_image);
5801 return WINED3DERR_INVALIDCALL;
5804 /* MSDN: Cursor must be smaller than the display mode */
5805 if (s->currentDesc.Width > This->ddraw_width
5806 || s->currentDesc.Height > This->ddraw_height)
5808 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5809 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5810 return WINED3DERR_INVALIDCALL;
5813 if (!This->haveHardwareCursor) {
5814 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5816 /* Do not store the surface's pointer because the application may
5817 * release it after setting the cursor image. Windows doesn't
5818 * addref the set surface, so we can't do this either without
5819 * creating circular refcount dependencies. Copy out the gl texture
5820 * instead.
5822 This->cursorWidth = s->currentDesc.Width;
5823 This->cursorHeight = s->currentDesc.Height;
5824 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5826 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5827 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5828 struct wined3d_context *context;
5829 char *mem, *bits = rect.pBits;
5830 GLint intfmt = format->glInternal;
5831 GLint gl_format = format->glFormat;
5832 GLint type = format->glType;
5833 INT height = This->cursorHeight;
5834 INT width = This->cursorWidth;
5835 INT bpp = format->byte_count;
5836 DWORD sampler;
5837 INT i;
5839 /* Reformat the texture memory (pitch and width can be
5840 * different) */
5841 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5842 for(i = 0; i < height; i++)
5843 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5844 IWineD3DSurface_Unmap(cursor_image);
5846 context = context_acquire(This, NULL);
5848 ENTER_GL();
5850 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5852 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5853 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5856 /* Make sure that a proper texture unit is selected */
5857 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5858 checkGLcall("glActiveTextureARB");
5859 sampler = This->rev_tex_unit_map[0];
5860 if (sampler != WINED3D_UNMAPPED_STAGE)
5862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5864 /* Create a new cursor texture */
5865 glGenTextures(1, &This->cursorTexture);
5866 checkGLcall("glGenTextures");
5867 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5868 checkGLcall("glBindTexture");
5869 /* Copy the bitmap memory into the cursor texture */
5870 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5871 checkGLcall("glTexImage2D");
5872 HeapFree(GetProcessHeap(), 0, mem);
5874 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5876 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5877 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5880 LEAVE_GL();
5882 context_release(context);
5884 else
5886 FIXME("A cursor texture was not returned.\n");
5887 This->cursorTexture = 0;
5890 else
5892 /* Draw a hardware cursor */
5893 ICONINFO cursorInfo;
5894 HCURSOR cursor;
5895 /* Create and clear maskBits because it is not needed for
5896 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5897 * chunks. */
5898 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5899 (s->currentDesc.Width * s->currentDesc.Height / 8));
5900 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5901 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5902 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5904 cursorInfo.fIcon = FALSE;
5905 cursorInfo.xHotspot = XHotSpot;
5906 cursorInfo.yHotspot = YHotSpot;
5907 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5908 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5909 IWineD3DSurface_Unmap(cursor_image);
5910 /* Create our cursor and clean up. */
5911 cursor = CreateIconIndirect(&cursorInfo);
5912 SetCursor(cursor);
5913 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5914 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5915 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5916 This->hardwareCursor = cursor;
5917 HeapFree(GetProcessHeap(), 0, maskBits);
5921 This->xHotSpot = XHotSpot;
5922 This->yHotSpot = YHotSpot;
5923 return WINED3D_OK;
5926 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5928 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5930 This->xScreenSpace = XScreenSpace;
5931 This->yScreenSpace = YScreenSpace;
5933 return;
5937 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5939 BOOL oldVisible = This->bCursorVisible;
5940 POINT pt;
5942 TRACE("(%p) : visible(%d)\n", This, bShow);
5945 * When ShowCursor is first called it should make the cursor appear at the OS's last
5946 * known cursor position. Because of this, some applications just repetitively call
5947 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5949 GetCursorPos(&pt);
5950 This->xScreenSpace = pt.x;
5951 This->yScreenSpace = pt.y;
5953 if (This->haveHardwareCursor) {
5954 This->bCursorVisible = bShow;
5955 if (bShow)
5956 SetCursor(This->hardwareCursor);
5957 else
5958 SetCursor(NULL);
5960 else
5962 if (This->cursorTexture)
5963 This->bCursorVisible = bShow;
5966 return oldVisible;
5969 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5970 TRACE("checking resource %p for eviction\n", resource);
5971 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5972 TRACE("Evicting %p\n", resource);
5973 IWineD3DResource_UnLoad(resource);
5975 IWineD3DResource_Release(resource);
5976 return S_OK;
5979 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5981 TRACE("iface %p.\n", iface);
5983 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5984 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5985 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
5987 return WINED3D_OK;
5990 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
5992 IWineD3DDeviceImpl *device = surface->resource.device;
5993 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5995 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5996 if(surface->Flags & SFLAG_DIBSECTION) {
5997 /* Release the DC */
5998 SelectObject(surface->hDC, surface->dib.holdbitmap);
5999 DeleteDC(surface->hDC);
6000 /* Release the DIB section */
6001 DeleteObject(surface->dib.DIBsection);
6002 surface->dib.bitmap_data = NULL;
6003 surface->resource.allocatedMemory = NULL;
6004 surface->Flags &= ~SFLAG_DIBSECTION;
6006 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6007 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6008 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6009 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6011 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6012 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6013 } else {
6014 surface->pow2Width = surface->pow2Height = 1;
6015 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6016 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6019 if (surface->texture_name)
6021 struct wined3d_context *context = context_acquire(device, NULL);
6022 ENTER_GL();
6023 glDeleteTextures(1, &surface->texture_name);
6024 LEAVE_GL();
6025 context_release(context);
6026 surface->texture_name = 0;
6027 surface->Flags &= ~SFLAG_CLIENT;
6029 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6030 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6031 surface->Flags |= SFLAG_NONPOW2;
6032 } else {
6033 surface->Flags &= ~SFLAG_NONPOW2;
6035 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6036 surface->resource.allocatedMemory = NULL;
6037 surface->resource.heapMemory = NULL;
6038 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6040 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6041 * to a FBO */
6042 if (!surface_init_sysmem(surface))
6044 return E_OUTOFMEMORY;
6046 return WINED3D_OK;
6049 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6050 TRACE("Unloading resource %p\n", resource);
6051 IWineD3DResource_UnLoad(resource);
6052 IWineD3DResource_Release(resource);
6053 return S_OK;
6056 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6058 UINT i, count;
6059 WINED3DDISPLAYMODE m;
6060 HRESULT hr;
6062 /* All Windowed modes are supported, as is leaving the current mode */
6063 if(pp->Windowed) return TRUE;
6064 if(!pp->BackBufferWidth) return TRUE;
6065 if(!pp->BackBufferHeight) return TRUE;
6067 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6068 for(i = 0; i < count; i++) {
6069 memset(&m, 0, sizeof(m));
6070 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6071 if(FAILED(hr)) {
6072 ERR("EnumAdapterModes failed\n");
6074 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6075 /* Mode found, it is supported */
6076 return TRUE;
6079 /* Mode not found -> not supported */
6080 return FALSE;
6083 /* Do not call while under the GL lock. */
6084 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6087 const struct wined3d_gl_info *gl_info;
6088 struct wined3d_context *context;
6089 IWineD3DBaseShaderImpl *shader;
6091 context = context_acquire(This, NULL);
6092 gl_info = context->gl_info;
6094 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6095 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6096 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6099 ENTER_GL();
6100 if(This->depth_blt_texture) {
6101 glDeleteTextures(1, &This->depth_blt_texture);
6102 This->depth_blt_texture = 0;
6104 if (This->depth_blt_rb) {
6105 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6106 This->depth_blt_rb = 0;
6107 This->depth_blt_rb_w = 0;
6108 This->depth_blt_rb_h = 0;
6110 LEAVE_GL();
6112 This->blitter->free_private(iface);
6113 This->frag_pipe->free_private(iface);
6114 This->shader_backend->shader_free_private(iface);
6115 destroy_dummy_textures(This, gl_info);
6117 context_release(context);
6119 while (This->numContexts)
6121 context_destroy(This, This->contexts[0]);
6123 HeapFree(GetProcessHeap(), 0, swapchain->context);
6124 swapchain->context = NULL;
6125 swapchain->num_contexts = 0;
6128 /* Do not call while under the GL lock. */
6129 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6132 struct wined3d_context *context;
6133 HRESULT hr;
6134 IWineD3DSurfaceImpl *target;
6136 /* Recreate the primary swapchain's context */
6137 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6138 if (!swapchain->context)
6140 ERR("Failed to allocate memory for swapchain context array.\n");
6141 return E_OUTOFMEMORY;
6144 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6145 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6147 WARN("Failed to create context.\n");
6148 HeapFree(GetProcessHeap(), 0, swapchain->context);
6149 return E_FAIL;
6152 swapchain->context[0] = context;
6153 swapchain->num_contexts = 1;
6154 create_dummy_textures(This);
6155 context_release(context);
6157 hr = This->shader_backend->shader_alloc_private(iface);
6158 if (FAILED(hr))
6160 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6161 goto err;
6164 hr = This->frag_pipe->alloc_private(iface);
6165 if (FAILED(hr))
6167 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6168 This->shader_backend->shader_free_private(iface);
6169 goto err;
6172 hr = This->blitter->alloc_private(iface);
6173 if (FAILED(hr))
6175 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6176 This->frag_pipe->free_private(iface);
6177 This->shader_backend->shader_free_private(iface);
6178 goto err;
6181 return WINED3D_OK;
6183 err:
6184 context_acquire(This, NULL);
6185 destroy_dummy_textures(This, context->gl_info);
6186 context_release(context);
6187 context_destroy(This, context);
6188 HeapFree(GetProcessHeap(), 0, swapchain->context);
6189 swapchain->num_contexts = 0;
6190 return hr;
6193 /* Do not call while under the GL lock. */
6194 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6195 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6198 IWineD3DSwapChainImpl *swapchain;
6199 HRESULT hr;
6200 BOOL DisplayModeChanged = FALSE;
6201 WINED3DDISPLAYMODE mode;
6202 TRACE("(%p)\n", This);
6204 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6205 if(FAILED(hr)) {
6206 ERR("Failed to get the first implicit swapchain\n");
6207 return hr;
6210 if(!is_display_mode_supported(This, pPresentationParameters)) {
6211 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6212 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6213 pPresentationParameters->BackBufferHeight);
6214 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6215 return WINED3DERR_INVALIDCALL;
6218 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6219 * on an existing gl context, so there's no real need for recreation.
6221 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6223 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6225 TRACE("New params:\n");
6226 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6227 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6228 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6229 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6230 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6231 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6232 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6233 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6234 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6235 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6236 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6237 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6238 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6240 /* No special treatment of these parameters. Just store them */
6241 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6242 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6243 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6244 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6246 /* What to do about these? */
6247 if (pPresentationParameters->BackBufferCount
6248 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6249 ERR("Cannot change the back buffer count yet\n");
6251 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6252 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6253 ERR("Cannot change the back buffer format yet\n");
6256 if (pPresentationParameters->hDeviceWindow
6257 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6258 ERR("Cannot change the device window yet\n");
6260 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6262 HRESULT hrc;
6264 TRACE("Creating the depth stencil buffer\n");
6266 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6267 pPresentationParameters->BackBufferWidth,
6268 pPresentationParameters->BackBufferHeight,
6269 pPresentationParameters->AutoDepthStencilFormat,
6270 pPresentationParameters->MultiSampleType,
6271 pPresentationParameters->MultiSampleQuality,
6272 FALSE,
6273 (IWineD3DSurface **)&This->auto_depth_stencil);
6275 if (FAILED(hrc)) {
6276 ERR("Failed to create the depth stencil buffer\n");
6277 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6278 return WINED3DERR_INVALIDCALL;
6282 if (This->onscreen_depth_stencil)
6284 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6285 This->onscreen_depth_stencil = NULL;
6288 /* Reset the depth stencil */
6289 if (pPresentationParameters->EnableAutoDepthStencil)
6290 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6291 else
6292 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6294 TRACE("Resetting stateblock\n");
6295 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6296 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6298 delete_opengl_contexts(iface, swapchain);
6300 if(pPresentationParameters->Windowed) {
6301 mode.Width = swapchain->orig_width;
6302 mode.Height = swapchain->orig_height;
6303 mode.RefreshRate = 0;
6304 mode.Format = swapchain->presentParms.BackBufferFormat;
6305 } else {
6306 mode.Width = pPresentationParameters->BackBufferWidth;
6307 mode.Height = pPresentationParameters->BackBufferHeight;
6308 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6309 mode.Format = swapchain->presentParms.BackBufferFormat;
6312 /* Should Width == 800 && Height == 0 set 800x600? */
6313 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6314 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6315 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6317 UINT i;
6319 if(!pPresentationParameters->Windowed) {
6320 DisplayModeChanged = TRUE;
6322 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6323 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6325 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6326 if(FAILED(hr))
6328 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6329 return hr;
6332 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6334 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6335 if(FAILED(hr))
6337 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6338 return hr;
6341 if (This->auto_depth_stencil)
6343 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6344 if(FAILED(hr))
6346 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6347 return hr;
6352 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6353 || DisplayModeChanged)
6355 BOOL filter = This->filter_messages;
6356 This->filter_messages = TRUE;
6358 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6360 if (!pPresentationParameters->Windowed)
6362 if (swapchain->presentParms.Windowed)
6364 HWND focus_window = This->createParms.hFocusWindow;
6365 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6366 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6368 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6369 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6370 return hr;
6373 /* switch from windowed to fs */
6374 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6375 pPresentationParameters->BackBufferHeight);
6377 else
6379 /* Fullscreen -> fullscreen mode change */
6380 MoveWindow(swapchain->device_window, 0, 0,
6381 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6382 TRUE);
6385 else if (!swapchain->presentParms.Windowed)
6387 /* Fullscreen -> windowed switch */
6388 swapchain_restore_fullscreen_window(swapchain);
6389 IWineD3DDevice_ReleaseFocusWindow(iface);
6391 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6393 This->filter_messages = filter;
6395 else if (!pPresentationParameters->Windowed)
6397 DWORD style = This->style, exStyle = This->exStyle;
6398 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6399 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6400 * Reset to clear up their mess. Guild Wars also loses the device during that.
6402 This->style = 0;
6403 This->exStyle = 0;
6404 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6405 pPresentationParameters->BackBufferHeight);
6406 This->style = style;
6407 This->exStyle = exStyle;
6410 /* Note: No parent needed for initial internal stateblock */
6411 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6412 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6413 else TRACE("Created stateblock %p\n", This->stateBlock);
6414 This->updateStateBlock = This->stateBlock;
6415 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6417 stateblock_init_default_state(This->stateBlock);
6419 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6421 RECT client_rect;
6422 GetClientRect(swapchain->win_handle, &client_rect);
6424 if(!swapchain->presentParms.BackBufferCount)
6426 TRACE("Single buffered rendering\n");
6427 swapchain->render_to_fbo = FALSE;
6429 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6430 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6432 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6433 swapchain->presentParms.BackBufferWidth,
6434 swapchain->presentParms.BackBufferHeight,
6435 client_rect.right, client_rect.bottom);
6436 swapchain->render_to_fbo = TRUE;
6438 else
6440 TRACE("Rendering directly to GL_BACK\n");
6441 swapchain->render_to_fbo = FALSE;
6445 hr = create_primary_opengl_context(iface, swapchain);
6446 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6448 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6449 * first use
6451 return hr;
6454 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6456 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6458 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6460 return WINED3D_OK;
6464 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6466 TRACE("(%p) : pParameters %p\n", This, pParameters);
6468 *pParameters = This->createParms;
6469 return WINED3D_OK;
6472 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6473 IWineD3DSwapChain *swapchain;
6475 TRACE("Relaying to swapchain\n");
6477 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6478 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6479 IWineD3DSwapChain_Release(swapchain);
6483 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6484 IWineD3DSwapChain *swapchain;
6486 TRACE("Relaying to swapchain\n");
6488 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6489 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6490 IWineD3DSwapChain_Release(swapchain);
6495 /** ********************************************************
6496 * Notification functions
6497 ** ********************************************************/
6498 /** This function must be called in the release of a resource when ref == 0,
6499 * the contents of resource must still be correct,
6500 * any handles to other resource held by the caller must be closed
6501 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6502 *****************************************************/
6503 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6505 TRACE("(%p) : Adding resource %p\n", This, resource);
6507 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6510 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6512 TRACE("(%p) : Removing resource %p\n", This, resource);
6514 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6517 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6519 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6520 unsigned int i;
6522 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6524 context_resource_released(device, resource, type);
6526 switch (type)
6528 case WINED3DRTYPE_SURFACE:
6529 if (!device->d3d_initialized) break;
6531 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6533 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6535 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6536 device->render_targets[i] = NULL;
6540 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6542 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6543 device->depth_stencil = NULL;
6545 break;
6547 case WINED3DRTYPE_TEXTURE:
6548 case WINED3DRTYPE_CUBETEXTURE:
6549 case WINED3DRTYPE_VOLUMETEXTURE:
6550 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6552 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6554 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6555 resource, device->stateBlock, i);
6556 device->stateBlock->state.textures[i] = NULL;
6559 if (device->updateStateBlock != device->stateBlock
6560 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6562 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6563 resource, device->updateStateBlock, i);
6564 device->updateStateBlock->state.textures[i] = NULL;
6567 break;
6569 case WINED3DRTYPE_BUFFER:
6570 for (i = 0; i < MAX_STREAMS; ++i)
6572 if (device->stateBlock
6573 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6575 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6576 resource, device->stateBlock, i);
6577 device->stateBlock->state.streams[i].buffer = NULL;
6580 if (device->updateStateBlock != device->stateBlock
6581 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6583 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6584 resource, device->updateStateBlock, i);
6585 device->updateStateBlock->state.streams[i].buffer = NULL;
6590 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6592 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6593 resource, device->stateBlock);
6594 device->stateBlock->state.index_buffer = NULL;
6597 if (device->updateStateBlock != device->stateBlock
6598 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6600 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6601 resource, device->updateStateBlock);
6602 device->updateStateBlock->state.index_buffer = NULL;
6604 break;
6606 default:
6607 break;
6610 /* Remove the resource from the resourceStore */
6611 device_resource_remove(device, resource);
6613 TRACE("Resource released.\n");
6616 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6618 IWineD3DResourceImpl *resource, *cursor;
6619 HRESULT ret;
6620 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6622 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6623 TRACE("enumerating resource %p\n", resource);
6624 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6625 ret = pCallback((IWineD3DResource *) resource, pData);
6626 if(ret == S_FALSE) {
6627 TRACE("Canceling enumeration\n");
6628 break;
6631 return WINED3D_OK;
6634 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6637 IWineD3DResourceImpl *resource;
6639 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6641 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6642 if (type == WINED3DRTYPE_SURFACE)
6644 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6646 TRACE("Found surface %p for dc %p.\n", resource, dc);
6647 *surface = (IWineD3DSurface *)resource;
6648 return WINED3D_OK;
6653 return WINED3DERR_INVALIDCALL;
6656 /**********************************************************
6657 * IWineD3DDevice VTbl follows
6658 **********************************************************/
6660 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6662 /*** IUnknown methods ***/
6663 IWineD3DDeviceImpl_QueryInterface,
6664 IWineD3DDeviceImpl_AddRef,
6665 IWineD3DDeviceImpl_Release,
6666 /*** IWineD3DDevice methods ***/
6667 /*** Creation methods**/
6668 IWineD3DDeviceImpl_CreateBuffer,
6669 IWineD3DDeviceImpl_CreateVertexBuffer,
6670 IWineD3DDeviceImpl_CreateIndexBuffer,
6671 IWineD3DDeviceImpl_CreateStateBlock,
6672 IWineD3DDeviceImpl_CreateSurface,
6673 IWineD3DDeviceImpl_CreateRendertargetView,
6674 IWineD3DDeviceImpl_CreateTexture,
6675 IWineD3DDeviceImpl_CreateVolumeTexture,
6676 IWineD3DDeviceImpl_CreateVolume,
6677 IWineD3DDeviceImpl_CreateCubeTexture,
6678 IWineD3DDeviceImpl_CreateQuery,
6679 IWineD3DDeviceImpl_CreateSwapChain,
6680 IWineD3DDeviceImpl_CreateVertexDeclaration,
6681 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6682 IWineD3DDeviceImpl_CreateVertexShader,
6683 IWineD3DDeviceImpl_CreateGeometryShader,
6684 IWineD3DDeviceImpl_CreatePixelShader,
6685 IWineD3DDeviceImpl_CreatePalette,
6686 /*** Odd functions **/
6687 IWineD3DDeviceImpl_Init3D,
6688 IWineD3DDeviceImpl_InitGDI,
6689 IWineD3DDeviceImpl_Uninit3D,
6690 IWineD3DDeviceImpl_UninitGDI,
6691 IWineD3DDeviceImpl_SetMultithreaded,
6692 IWineD3DDeviceImpl_EvictManagedResources,
6693 IWineD3DDeviceImpl_GetAvailableTextureMem,
6694 IWineD3DDeviceImpl_GetBackBuffer,
6695 IWineD3DDeviceImpl_GetCreationParameters,
6696 IWineD3DDeviceImpl_GetDeviceCaps,
6697 IWineD3DDeviceImpl_GetDirect3D,
6698 IWineD3DDeviceImpl_GetDisplayMode,
6699 IWineD3DDeviceImpl_SetDisplayMode,
6700 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6701 IWineD3DDeviceImpl_GetRasterStatus,
6702 IWineD3DDeviceImpl_GetSwapChain,
6703 IWineD3DDeviceImpl_Reset,
6704 IWineD3DDeviceImpl_SetDialogBoxMode,
6705 IWineD3DDeviceImpl_SetCursorProperties,
6706 IWineD3DDeviceImpl_SetCursorPosition,
6707 IWineD3DDeviceImpl_ShowCursor,
6708 /*** Getters and setters **/
6709 IWineD3DDeviceImpl_SetClipPlane,
6710 IWineD3DDeviceImpl_GetClipPlane,
6711 IWineD3DDeviceImpl_SetClipStatus,
6712 IWineD3DDeviceImpl_GetClipStatus,
6713 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6714 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6715 IWineD3DDeviceImpl_SetDepthStencilSurface,
6716 IWineD3DDeviceImpl_GetDepthStencilSurface,
6717 IWineD3DDeviceImpl_SetGammaRamp,
6718 IWineD3DDeviceImpl_GetGammaRamp,
6719 IWineD3DDeviceImpl_SetIndexBuffer,
6720 IWineD3DDeviceImpl_GetIndexBuffer,
6721 IWineD3DDeviceImpl_SetBaseVertexIndex,
6722 IWineD3DDeviceImpl_GetBaseVertexIndex,
6723 IWineD3DDeviceImpl_SetLight,
6724 IWineD3DDeviceImpl_GetLight,
6725 IWineD3DDeviceImpl_SetLightEnable,
6726 IWineD3DDeviceImpl_GetLightEnable,
6727 IWineD3DDeviceImpl_SetMaterial,
6728 IWineD3DDeviceImpl_GetMaterial,
6729 IWineD3DDeviceImpl_SetNPatchMode,
6730 IWineD3DDeviceImpl_GetNPatchMode,
6731 IWineD3DDeviceImpl_SetPaletteEntries,
6732 IWineD3DDeviceImpl_GetPaletteEntries,
6733 IWineD3DDeviceImpl_SetPixelShader,
6734 IWineD3DDeviceImpl_GetPixelShader,
6735 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6736 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6737 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6738 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6739 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6740 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6741 IWineD3DDeviceImpl_SetRenderState,
6742 IWineD3DDeviceImpl_GetRenderState,
6743 IWineD3DDeviceImpl_SetRenderTarget,
6744 IWineD3DDeviceImpl_GetRenderTarget,
6745 IWineD3DDeviceImpl_SetSamplerState,
6746 IWineD3DDeviceImpl_GetSamplerState,
6747 IWineD3DDeviceImpl_SetScissorRect,
6748 IWineD3DDeviceImpl_GetScissorRect,
6749 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6750 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6751 IWineD3DDeviceImpl_SetStreamSource,
6752 IWineD3DDeviceImpl_GetStreamSource,
6753 IWineD3DDeviceImpl_SetStreamSourceFreq,
6754 IWineD3DDeviceImpl_GetStreamSourceFreq,
6755 IWineD3DDeviceImpl_SetTexture,
6756 IWineD3DDeviceImpl_GetTexture,
6757 IWineD3DDeviceImpl_SetTextureStageState,
6758 IWineD3DDeviceImpl_GetTextureStageState,
6759 IWineD3DDeviceImpl_SetTransform,
6760 IWineD3DDeviceImpl_GetTransform,
6761 IWineD3DDeviceImpl_SetVertexDeclaration,
6762 IWineD3DDeviceImpl_GetVertexDeclaration,
6763 IWineD3DDeviceImpl_SetVertexShader,
6764 IWineD3DDeviceImpl_GetVertexShader,
6765 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6766 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6767 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6768 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6769 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6770 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6771 IWineD3DDeviceImpl_SetViewport,
6772 IWineD3DDeviceImpl_GetViewport,
6773 IWineD3DDeviceImpl_MultiplyTransform,
6774 IWineD3DDeviceImpl_ValidateDevice,
6775 IWineD3DDeviceImpl_ProcessVertices,
6776 /*** State block ***/
6777 IWineD3DDeviceImpl_BeginStateBlock,
6778 IWineD3DDeviceImpl_EndStateBlock,
6779 /*** Scene management ***/
6780 IWineD3DDeviceImpl_BeginScene,
6781 IWineD3DDeviceImpl_EndScene,
6782 IWineD3DDeviceImpl_Present,
6783 IWineD3DDeviceImpl_Clear,
6784 IWineD3DDeviceImpl_ClearRendertargetView,
6785 /*** Drawing ***/
6786 IWineD3DDeviceImpl_SetPrimitiveType,
6787 IWineD3DDeviceImpl_GetPrimitiveType,
6788 IWineD3DDeviceImpl_DrawPrimitive,
6789 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6790 IWineD3DDeviceImpl_DrawPrimitiveUP,
6791 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6792 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6793 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6794 IWineD3DDeviceImpl_DrawRectPatch,
6795 IWineD3DDeviceImpl_DrawTriPatch,
6796 IWineD3DDeviceImpl_DeletePatch,
6797 IWineD3DDeviceImpl_ColorFill,
6798 IWineD3DDeviceImpl_UpdateTexture,
6799 IWineD3DDeviceImpl_UpdateSurface,
6800 IWineD3DDeviceImpl_GetFrontBufferData,
6801 /*** object tracking ***/
6802 IWineD3DDeviceImpl_EnumResources,
6803 IWineD3DDeviceImpl_GetSurfaceFromDC,
6804 IWineD3DDeviceImpl_AcquireFocusWindow,
6805 IWineD3DDeviceImpl_ReleaseFocusWindow,
6808 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6809 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6810 IWineD3DDeviceParent *device_parent)
6812 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6813 const struct fragment_pipeline *fragment_pipeline;
6814 struct shader_caps shader_caps;
6815 struct fragment_caps ffp_caps;
6816 WINED3DDISPLAYMODE mode;
6817 unsigned int i;
6818 HRESULT hr;
6820 device->lpVtbl = &IWineD3DDevice_Vtbl;
6821 device->ref = 1;
6822 device->wined3d = (IWineD3D *)wined3d;
6823 IWineD3D_AddRef(device->wined3d);
6824 device->adapter = wined3d->adapter_count ? adapter : NULL;
6825 device->device_parent = device_parent;
6826 list_init(&device->resources);
6827 list_init(&device->shaders);
6829 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6831 /* Get the initial screen setup for ddraw. */
6832 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6833 if (FAILED(hr))
6835 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6836 IWineD3D_Release(device->wined3d);
6837 return hr;
6839 device->ddraw_width = mode.Width;
6840 device->ddraw_height = mode.Height;
6841 device->ddraw_format = mode.Format;
6843 /* Save the creation parameters. */
6844 device->createParms.AdapterOrdinal = adapter_idx;
6845 device->createParms.DeviceType = device_type;
6846 device->createParms.hFocusWindow = focus_window;
6847 device->createParms.BehaviorFlags = flags;
6849 device->devType = device_type;
6850 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6852 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6853 device->shader_backend = adapter->shader_backend;
6855 if (device->shader_backend)
6857 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6858 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6859 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6860 device->vs_clipping = shader_caps.VSClipping;
6862 fragment_pipeline = adapter->fragment_pipe;
6863 device->frag_pipe = fragment_pipeline;
6864 if (fragment_pipeline)
6866 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6867 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6869 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6870 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6871 if (FAILED(hr))
6873 ERR("Failed to compile state table, hr %#x.\n", hr);
6874 IWineD3D_Release(device->wined3d);
6875 return hr;
6878 device->blitter = adapter->blitter;
6880 return WINED3D_OK;
6884 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6885 DWORD rep = This->StateTable[state].representative;
6886 struct wined3d_context *context;
6887 DWORD idx;
6888 BYTE shift;
6889 UINT i;
6891 for(i = 0; i < This->numContexts; i++) {
6892 context = This->contexts[i];
6893 if(isStateDirty(context, rep)) continue;
6895 context->dirtyArray[context->numDirtyEntries++] = rep;
6896 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6897 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6898 context->isStateDirty[idx] |= (1 << shift);
6902 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6904 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6905 *width = context->current_rt->pow2Width;
6906 *height = context->current_rt->pow2Height;
6909 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6911 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6912 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6913 * current context's drawable, which is the size of the back buffer of the swapchain
6914 * the active context belongs to. */
6915 *width = swapchain->presentParms.BackBufferWidth;
6916 *height = swapchain->presentParms.BackBufferHeight;
6919 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
6920 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6922 if (device->filter_messages)
6924 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6925 window, message, wparam, lparam);
6926 if (unicode)
6927 return DefWindowProcW(window, message, wparam, lparam);
6928 else
6929 return DefWindowProcA(window, message, wparam, lparam);
6932 if (message == WM_DESTROY)
6934 TRACE("unregister window %p.\n", window);
6935 wined3d_unregister_window(window);
6937 if (device->focus_window == window) device->focus_window = NULL;
6938 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6941 if (unicode)
6942 return CallWindowProcW(proc, window, message, wparam, lparam);
6943 else
6944 return CallWindowProcA(proc, window, message, wparam, lparam);