taskkill: Add Lithuanian translation.
[wine.git] / dlls / wined3d / device.c
blob89ddb856c10031d2f643b12be8432ab4c7c4ed08
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 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
412 BOOL vs = stateblock->state.vertex_shader && device->vs_selected_mode != SHADER_NONE;
413 BOOL fixup = FALSE;
415 if (device->up_strided)
417 /* Note: this is a ddraw fixed-function code path. */
418 TRACE("=============================== Strided Input ================================\n");
419 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
420 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
422 else
424 TRACE("============================= Vertex Declaration =============================\n");
425 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
428 if (vs && !stream_info->position_transformed)
430 if (stateblock->state.vertex_declaration->half_float_conv_needed && !fixup)
432 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
433 device->useDrawStridedSlow = TRUE;
435 else
437 device->useDrawStridedSlow = FALSE;
440 else
442 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
443 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
444 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
446 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
448 device->useDrawStridedSlow = TRUE;
450 else
452 device->useDrawStridedSlow = FALSE;
457 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
459 IWineD3DBaseTextureImpl *texture;
460 enum WINED3DSRGB srgb;
462 if (!(texture = stateblock->state.textures[idx])) return;
463 srgb = stateblock->state.sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
464 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
467 void device_preload_textures(IWineD3DDeviceImpl *device)
469 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
470 unsigned int i;
472 if (use_vs(stateblock))
474 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
476 if (stateblock->state.vertex_shader->baseShader.reg_maps.sampler_type[i])
477 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
481 if (use_ps(stateblock))
483 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
485 if (stateblock->state.pixel_shader->baseShader.reg_maps.sampler_type[i])
486 device_preload_texture(stateblock, i);
489 else
491 WORD ffu_map = device->fixed_function_usage_map;
493 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 if (ffu_map & 1)
496 device_preload_texture(stateblock, i);
501 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
503 struct wined3d_context **new_array;
505 TRACE("Adding context %p.\n", context);
507 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
508 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
510 if (!new_array)
512 ERR("Failed to grow the context array.\n");
513 return FALSE;
516 new_array[device->numContexts++] = context;
517 device->contexts = new_array;
518 return TRUE;
521 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
523 struct wined3d_context **new_array;
524 BOOL found = FALSE;
525 UINT i;
527 TRACE("Removing context %p.\n", context);
529 for (i = 0; i < device->numContexts; ++i)
531 if (device->contexts[i] == context)
533 found = TRUE;
534 break;
538 if (!found)
540 ERR("Context %p doesn't exist in context array.\n", context);
541 return;
544 if (!--device->numContexts)
546 HeapFree(GetProcessHeap(), 0, device->contexts);
547 device->contexts = NULL;
548 return;
551 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
552 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
553 if (!new_array)
555 ERR("Failed to shrink context array. Oh well.\n");
556 return;
559 device->contexts = new_array;
562 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
564 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
565 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
567 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
569 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
571 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
575 /* Do not call while under the GL lock. */
576 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
577 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
579 if (device->onscreen_depth_stencil)
581 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
582 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
583 device->onscreen_depth_stencil->ds_current_size.cx,
584 device->onscreen_depth_stencil->ds_current_size.cy);
585 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
587 device->onscreen_depth_stencil = depth_stencil;
588 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
591 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
593 /* partial draw rect */
594 if (draw_rect->left || draw_rect->top
595 || draw_rect->right < target->currentDesc.Width
596 || draw_rect->bottom < target->currentDesc.Height)
597 return FALSE;
599 /* partial clear rect */
600 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
601 || clear_rect->right < target->currentDesc.Width
602 || clear_rect->bottom < target->currentDesc.Height))
603 return FALSE;
605 return TRUE;
608 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
609 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
611 RECT current_rect, r;
613 if (ds->Flags & location)
614 SetRect(&current_rect, 0, 0,
615 ds->ds_current_size.cx,
616 ds->ds_current_size.cy);
617 else
618 SetRectEmpty(&current_rect);
620 IntersectRect(&r, draw_rect, &current_rect);
621 if (EqualRect(&r, draw_rect))
623 /* current_rect ⊇ draw_rect, modify only. */
624 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
625 return;
628 if (EqualRect(&r, &current_rect))
630 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
632 if (!clear_rect)
634 /* Full clear, modify only. */
635 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
636 return;
639 IntersectRect(&r, draw_rect, clear_rect);
640 if (EqualRect(&r, draw_rect))
642 /* clear_rect ⊇ draw_rect, modify only. */
643 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
644 return;
648 /* Full load. */
649 surface_load_ds_location(ds, context, location);
650 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
653 /* Do not call while under the GL lock. */
654 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
655 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
656 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
658 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
659 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
660 IWineD3DSurfaceImpl *target = rts[0];
661 UINT drawable_width, drawable_height;
662 struct wined3d_context *context;
663 GLbitfield clear_mask = 0;
664 unsigned int i;
666 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
667 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
668 * for the cleared parts, and the untouched parts.
670 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
671 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
672 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
673 * checking all this if the dest surface is in the drawable anyway. */
674 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
676 for (i = 0; i < rt_count; ++i)
678 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
682 context = context_acquire(device, target);
683 if (!context->valid)
685 context_release(context);
686 WARN("Invalid context, skipping clear.\n");
687 return WINED3D_OK;
690 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
692 target->get_drawable_size(context, &drawable_width, &drawable_height);
694 ENTER_GL();
696 /* Only set the values up once, as they are not changing. */
697 if (flags & WINED3DCLEAR_STENCIL)
699 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
701 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
702 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 glStencilMask(~0U);
705 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
706 glClearStencil(stencil);
707 checkGLcall("glClearStencil");
708 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
711 if (flags & WINED3DCLEAR_ZBUFFER)
713 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
715 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 LEAVE_GL();
718 device_switch_onscreen_ds(device, context, depth_stencil);
719 ENTER_GL();
721 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
722 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
724 glDepthMask(GL_TRUE);
725 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 glClearDepth(depth);
727 checkGLcall("glClearDepth");
728 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
731 if (flags & WINED3DCLEAR_TARGET)
733 for (i = 0; i < rt_count; ++i)
735 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
738 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
743 glClearColor(color->r, color->g, color->b, color->a);
744 checkGLcall("glClearColor");
745 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
748 if (!clear_rect)
750 if (context->render_offscreen)
752 glScissor(draw_rect->left, draw_rect->top,
753 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
755 else
757 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
758 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
760 checkGLcall("glScissor");
761 glClear(clear_mask);
762 checkGLcall("glClear");
764 else
766 RECT current_rect;
768 /* Now process each rect in turn. */
769 for (i = 0; i < rect_count; ++i)
771 /* Note that GL uses lower left, width/height. */
772 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
774 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
775 wine_dbgstr_rect(&clear_rect[i]),
776 wine_dbgstr_rect(&current_rect));
778 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
779 * The rectangle is not cleared, no error is returned, but further rectanlges are
780 * still cleared if they are valid. */
781 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
783 TRACE("Rectangle with negative dimensions, ignoring.\n");
784 continue;
787 if (context->render_offscreen)
789 glScissor(current_rect.left, current_rect.top,
790 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
792 else
794 glScissor(current_rect.left, drawable_height - current_rect.bottom,
795 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
797 checkGLcall("glScissor");
799 glClear(clear_mask);
800 checkGLcall("glClear");
804 LEAVE_GL();
806 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
807 && target->container.u.swapchain->front_buffer == target))
808 wglFlush(); /* Flush to ensure ordering across contexts. */
810 context_release(context);
812 return WINED3D_OK;
816 /**********************************************************
817 * IUnknown parts follows
818 **********************************************************/
820 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
822 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
824 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
825 || IsEqualGUID(riid, &IID_IUnknown))
827 IUnknown_AddRef(iface);
828 *object = iface;
829 return S_OK;
832 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 *object = NULL;
835 return E_NOINTERFACE;
838 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
840 ULONG refCount = InterlockedIncrement(&This->ref);
842 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
843 return refCount;
846 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 ULONG refCount = InterlockedDecrement(&This->ref);
850 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
852 if (!refCount) {
853 UINT i;
855 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
856 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
857 This->multistate_funcs[i] = NULL;
860 /* TODO: Clean up all the surfaces and textures! */
861 /* NOTE: You must release the parent if the object was created via a callback
862 ** ***************************/
864 if (!list_empty(&This->resources))
866 IWineD3DResourceImpl *resource;
867 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
869 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
871 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
872 FIXME("Leftover resource %p with type %s (%#x).\n",
873 resource, debug_d3dresourcetype(type), type);
877 if(This->contexts) ERR("Context array not freed!\n");
878 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
879 This->haveHardwareCursor = FALSE;
881 IWineD3D_Release(This->wined3d);
882 This->wined3d = NULL;
883 HeapFree(GetProcessHeap(), 0, This);
884 TRACE("Freed device %p\n", This);
885 This = NULL;
887 return refCount;
890 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
891 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
894 struct wined3d_buffer *object;
895 HRESULT hr;
897 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
899 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
900 if (!object)
902 ERR("Failed to allocate memory\n");
903 return E_OUTOFMEMORY;
906 FIXME("Ignoring access flags (pool)\n");
908 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
909 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
910 if (FAILED(hr))
912 WARN("Failed to initialize buffer, hr %#x.\n", hr);
913 HeapFree(GetProcessHeap(), 0, object);
914 return hr;
916 object->desc = *desc;
918 TRACE("Created buffer %p.\n", object);
920 *buffer = (IWineD3DBuffer *)object;
922 return WINED3D_OK;
925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
926 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
927 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
930 struct wined3d_buffer *object;
931 HRESULT hr;
933 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
934 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
936 if (Pool == WINED3DPOOL_SCRATCH)
938 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
939 * anyway, SCRATCH vertex buffers aren't usable anywhere
941 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
942 *ppVertexBuffer = NULL;
943 return WINED3DERR_INVALIDCALL;
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
947 if (!object)
949 ERR("Out of memory\n");
950 *ppVertexBuffer = NULL;
951 return WINED3DERR_OUTOFVIDEOMEMORY;
954 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
955 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
956 if (FAILED(hr))
958 WARN("Failed to initialize buffer, hr %#x.\n", hr);
959 HeapFree(GetProcessHeap(), 0, object);
960 return hr;
963 TRACE("Created buffer %p.\n", object);
964 *ppVertexBuffer = (IWineD3DBuffer *)object;
966 return WINED3D_OK;
969 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
970 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
971 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
974 struct wined3d_buffer *object;
975 HRESULT hr;
977 TRACE("(%p) Creating index buffer\n", This);
979 /* Allocate the storage for the device */
980 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
981 if (!object)
983 ERR("Out of memory\n");
984 *ppIndexBuffer = NULL;
985 return WINED3DERR_OUTOFVIDEOMEMORY;
988 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
989 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
990 parent, parent_ops);
991 if (FAILED(hr))
993 WARN("Failed to initialize buffer, hr %#x\n", hr);
994 HeapFree(GetProcessHeap(), 0, object);
995 return hr;
998 TRACE("Created buffer %p.\n", object);
1000 *ppIndexBuffer = (IWineD3DBuffer *) object;
1002 return WINED3D_OK;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1006 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DStateBlockImpl *object;
1010 HRESULT hr;
1012 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1013 if(!object)
1015 ERR("Failed to allocate stateblock memory.\n");
1016 return E_OUTOFMEMORY;
1019 hr = stateblock_init(object, This, type);
1020 if (FAILED(hr))
1022 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1023 HeapFree(GetProcessHeap(), 0, object);
1024 return hr;
1027 TRACE("Created stateblock %p.\n", object);
1028 *stateblock = (IWineD3DStateBlock *)object;
1030 return WINED3D_OK;
1033 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1034 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1035 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1036 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1039 IWineD3DSurfaceImpl *object;
1040 HRESULT hr;
1042 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1043 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1044 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1045 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1046 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1048 if (Impl == SURFACE_OPENGL && !This->adapter)
1050 ERR("OpenGL surfaces are not available without OpenGL.\n");
1051 return WINED3DERR_NOTAVAILABLE;
1054 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1055 if (!object)
1057 ERR("Failed to allocate surface memory.\n");
1058 return WINED3DERR_OUTOFVIDEOMEMORY;
1061 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1062 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1063 if (FAILED(hr))
1065 WARN("Failed to initialize surface, returning %#x.\n", hr);
1066 HeapFree(GetProcessHeap(), 0, object);
1067 return hr;
1070 TRACE("(%p) : Created surface %p\n", This, object);
1072 *surface = (IWineD3DSurface *)object;
1074 return hr;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1078 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1080 struct wined3d_rendertarget_view *object;
1082 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1083 iface, resource, parent, rendertarget_view);
1085 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1086 if (!object)
1088 ERR("Failed to allocate memory\n");
1089 return E_OUTOFMEMORY;
1092 wined3d_rendertarget_view_init(object, resource, parent);
1094 TRACE("Created render target view %p.\n", object);
1095 *rendertarget_view = (IWineD3DRendertargetView *)object;
1097 return WINED3D_OK;
1100 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1101 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1102 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1105 IWineD3DTextureImpl *object;
1106 HRESULT hr;
1108 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1109 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1110 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1112 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1113 if (!object)
1115 ERR("Out of memory\n");
1116 *ppTexture = NULL;
1117 return WINED3DERR_OUTOFVIDEOMEMORY;
1120 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1121 if (FAILED(hr))
1123 WARN("Failed to initialize texture, returning %#x\n", hr);
1124 HeapFree(GetProcessHeap(), 0, object);
1125 *ppTexture = NULL;
1126 return hr;
1129 *ppTexture = (IWineD3DTexture *)object;
1131 TRACE("(%p) : Created texture %p\n", This, object);
1133 return WINED3D_OK;
1136 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1137 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1138 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141 IWineD3DVolumeTextureImpl *object;
1142 HRESULT hr;
1144 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1145 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1147 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1148 if (!object)
1150 ERR("Out of memory\n");
1151 *ppVolumeTexture = NULL;
1152 return WINED3DERR_OUTOFVIDEOMEMORY;
1155 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1156 if (FAILED(hr))
1158 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1159 HeapFree(GetProcessHeap(), 0, object);
1160 *ppVolumeTexture = NULL;
1161 return hr;
1164 TRACE("(%p) : Created volume texture %p.\n", This, object);
1165 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1167 return WINED3D_OK;
1170 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1171 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1172 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1175 IWineD3DVolumeImpl *object;
1176 HRESULT hr;
1178 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1179 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1181 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1182 if (!object)
1184 ERR("Out of memory\n");
1185 *ppVolume = NULL;
1186 return WINED3DERR_OUTOFVIDEOMEMORY;
1189 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1190 if (FAILED(hr))
1192 WARN("Failed to initialize volume, returning %#x.\n", hr);
1193 HeapFree(GetProcessHeap(), 0, object);
1194 return hr;
1197 TRACE("(%p) : Created volume %p.\n", This, object);
1198 *ppVolume = (IWineD3DVolume *)object;
1200 return WINED3D_OK;
1203 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1204 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1205 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1208 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1209 HRESULT hr;
1211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1212 if (!object)
1214 ERR("Out of memory\n");
1215 *ppCubeTexture = NULL;
1216 return WINED3DERR_OUTOFVIDEOMEMORY;
1219 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1220 if (FAILED(hr))
1222 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1223 HeapFree(GetProcessHeap(), 0, object);
1224 *ppCubeTexture = NULL;
1225 return hr;
1228 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1229 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1231 return WINED3D_OK;
1234 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1235 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1238 IWineD3DQueryImpl *object;
1239 HRESULT hr;
1241 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1243 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1244 if (!object)
1246 ERR("Failed to allocate query memory.\n");
1247 return E_OUTOFMEMORY;
1250 hr = query_init(object, This, type);
1251 if (FAILED(hr))
1253 WARN("Failed to initialize query, hr %#x.\n", hr);
1254 HeapFree(GetProcessHeap(), 0, object);
1255 return hr;
1258 TRACE("Created query %p.\n", object);
1259 *query = (IWineD3DQuery *)object;
1261 return WINED3D_OK;
1264 /* Do not call while under the GL lock. */
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1266 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1267 void *parent, IWineD3DSwapChain **swapchain)
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 IWineD3DSwapChainImpl *object;
1271 HRESULT hr;
1273 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1274 iface, present_parameters, swapchain, parent, surface_type);
1276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1277 if (!object)
1279 ERR("Failed to allocate swapchain memory.\n");
1280 return E_OUTOFMEMORY;
1283 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1284 if (FAILED(hr))
1286 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1287 HeapFree(GetProcessHeap(), 0, object);
1288 return hr;
1291 TRACE("Created swapchain %p.\n", object);
1292 *swapchain = (IWineD3DSwapChain *)object;
1294 return WINED3D_OK;
1297 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1298 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1300 TRACE("(%p)\n", This);
1302 return This->NumberOfSwapChains;
1305 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1307 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1309 if(iSwapChain < This->NumberOfSwapChains) {
1310 *pSwapChain = This->swapchains[iSwapChain];
1311 IWineD3DSwapChain_AddRef(*pSwapChain);
1312 TRACE("(%p) returning %p\n", This, *pSwapChain);
1313 return WINED3D_OK;
1314 } else {
1315 TRACE("Swapchain out of range\n");
1316 *pSwapChain = NULL;
1317 return WINED3DERR_INVALIDCALL;
1321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1322 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1323 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 IWineD3DVertexDeclarationImpl *object = NULL;
1327 HRESULT hr;
1329 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1330 iface, declaration, parent, elements, element_count);
1332 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1333 if(!object)
1335 ERR("Failed to allocate vertex declaration memory.\n");
1336 return E_OUTOFMEMORY;
1339 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1340 if (FAILED(hr))
1342 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1343 HeapFree(GetProcessHeap(), 0, object);
1344 return hr;
1347 TRACE("Created vertex declaration %p.\n", object);
1348 *declaration = (IWineD3DVertexDeclaration *)object;
1350 return WINED3D_OK;
1353 struct wined3d_fvf_convert_state
1355 const struct wined3d_gl_info *gl_info;
1356 WINED3DVERTEXELEMENT *elements;
1357 UINT offset;
1358 UINT idx;
1361 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1362 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1364 WINED3DVERTEXELEMENT *elements = state->elements;
1365 const struct wined3d_format *format;
1366 UINT offset = state->offset;
1367 UINT idx = state->idx;
1369 elements[idx].format = format_id;
1370 elements[idx].input_slot = 0;
1371 elements[idx].offset = offset;
1372 elements[idx].output_slot = 0;
1373 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1374 elements[idx].usage = usage;
1375 elements[idx].usage_idx = usage_idx;
1377 format = wined3d_get_format(state->gl_info, format_id);
1378 state->offset += format->component_count * format->component_size;
1379 ++state->idx;
1382 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1383 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1385 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1386 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1387 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1388 BOOL has_blend_idx = has_blend &&
1389 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1390 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1391 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1392 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1393 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1394 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1395 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1397 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1398 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1399 struct wined3d_fvf_convert_state state;
1400 unsigned int size;
1401 unsigned int idx;
1402 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1403 if (has_blend_idx) num_blends--;
1405 /* Compute declaration size */
1406 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1407 has_psize + has_diffuse + has_specular + num_textures;
1409 state.gl_info = gl_info;
1410 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1411 if (!state.elements) return ~0U;
1412 state.offset = 0;
1413 state.idx = 0;
1415 if (has_pos)
1417 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1418 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1419 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1420 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1421 else
1422 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1425 if (has_blend && (num_blends > 0))
1427 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1428 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1429 else
1431 switch (num_blends)
1433 case 1:
1434 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1435 break;
1436 case 2:
1437 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 break;
1439 case 3:
1440 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 break;
1442 case 4:
1443 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 break;
1445 default:
1446 ERR("Unexpected amount of blend values: %u\n", num_blends);
1451 if (has_blend_idx)
1453 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1454 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1455 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1456 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1457 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1458 else
1459 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1463 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1464 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1465 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1467 for (idx = 0; idx < num_textures; ++idx)
1469 switch ((texcoords >> (idx * 2)) & 0x03)
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1473 break;
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 break;
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 break;
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 break;
1486 *ppVertexElements = state.elements;
1487 return size;
1490 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1491 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1492 IWineD3DVertexDeclaration **declaration)
1494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1495 WINED3DVERTEXELEMENT *elements;
1496 unsigned int size;
1497 DWORD hr;
1499 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1501 size = ConvertFvfToDeclaration(This, fvf, &elements);
1502 if (size == ~0U) return E_OUTOFMEMORY;
1504 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1505 HeapFree(GetProcessHeap(), 0, elements);
1506 return hr;
1509 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1510 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1511 void *parent, const struct wined3d_parent_ops *parent_ops,
1512 IWineD3DVertexShader **ppVertexShader)
1514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1515 IWineD3DVertexShaderImpl *object;
1516 HRESULT hr;
1518 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1519 if (!object)
1521 ERR("Failed to allocate shader memory.\n");
1522 return E_OUTOFMEMORY;
1525 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1526 if (FAILED(hr))
1528 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1529 HeapFree(GetProcessHeap(), 0, object);
1530 return hr;
1533 TRACE("Created vertex shader %p.\n", object);
1534 *ppVertexShader = (IWineD3DVertexShader *)object;
1536 return WINED3D_OK;
1539 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1540 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1541 void *parent, const struct wined3d_parent_ops *parent_ops,
1542 IWineD3DGeometryShader **shader)
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 struct wined3d_geometryshader *object;
1546 HRESULT hr;
1548 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1549 if (!object)
1551 ERR("Failed to allocate shader memory.\n");
1552 return E_OUTOFMEMORY;
1555 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1556 if (FAILED(hr))
1558 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1559 HeapFree(GetProcessHeap(), 0, object);
1560 return hr;
1563 TRACE("Created geometry shader %p.\n", object);
1564 *shader = (IWineD3DGeometryShader *)object;
1566 return WINED3D_OK;
1569 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1570 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1571 void *parent, const struct wined3d_parent_ops *parent_ops,
1572 IWineD3DPixelShader **ppPixelShader)
1574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1575 IWineD3DPixelShaderImpl *object;
1576 HRESULT hr;
1578 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1579 if (!object)
1581 ERR("Failed to allocate shader memory.\n");
1582 return E_OUTOFMEMORY;
1585 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1586 if (FAILED(hr))
1588 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1589 HeapFree(GetProcessHeap(), 0, object);
1590 return hr;
1593 TRACE("Created pixel shader %p.\n", object);
1594 *ppPixelShader = (IWineD3DPixelShader *)object;
1596 return WINED3D_OK;
1599 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1600 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1603 IWineD3DPaletteImpl *object;
1604 HRESULT hr;
1606 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1607 iface, Flags, PalEnt, Palette, parent);
1609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1610 if (!object)
1612 ERR("Failed to allocate palette memory.\n");
1613 return E_OUTOFMEMORY;
1616 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1617 if (FAILED(hr))
1619 WARN("Failed to initialize palette, hr %#x.\n", hr);
1620 HeapFree(GetProcessHeap(), 0, object);
1621 return hr;
1624 TRACE("Created palette %p.\n", object);
1625 *Palette = (IWineD3DPalette *)object;
1627 return WINED3D_OK;
1630 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1631 HBITMAP hbm;
1632 BITMAP bm;
1633 HRESULT hr;
1634 HDC dcb = NULL, dcs = NULL;
1635 WINEDDCOLORKEY colorkey;
1637 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1638 if(hbm)
1640 GetObjectA(hbm, sizeof(BITMAP), &bm);
1641 dcb = CreateCompatibleDC(NULL);
1642 if(!dcb) goto out;
1643 SelectObject(dcb, hbm);
1645 else
1647 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1648 * couldn't be loaded
1650 memset(&bm, 0, sizeof(bm));
1651 bm.bmWidth = 32;
1652 bm.bmHeight = 32;
1655 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1656 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1657 &wined3d_null_parent_ops, &This->logo_surface);
1658 if (FAILED(hr))
1660 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1661 goto out;
1664 if(dcb) {
1665 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1666 if(FAILED(hr)) goto out;
1667 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1668 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1670 colorkey.dwColorSpaceLowValue = 0;
1671 colorkey.dwColorSpaceHighValue = 0;
1672 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1674 else
1676 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1677 /* Fill the surface with a white color to show that wined3d is there */
1678 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1681 out:
1682 if (dcb) DeleteDC(dcb);
1683 if (hbm) DeleteObject(hbm);
1686 /* Context activation is done by the caller. */
1687 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1689 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1690 unsigned int i;
1691 /* Under DirectX you can have texture stage operations even if no texture is
1692 bound, whereas opengl will only do texture operations when a valid texture is
1693 bound. We emulate this by creating dummy textures and binding them to each
1694 texture stage, but disable all stages by default. Hence if a stage is enabled
1695 then the default texture will kick in until replaced by a SetTexture call */
1696 ENTER_GL();
1698 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1700 /* The dummy texture does not have client storage backing */
1701 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1702 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1705 for (i = 0; i < gl_info->limits.textures; ++i)
1707 GLubyte white = 255;
1709 /* Make appropriate texture active */
1710 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1711 checkGLcall("glActiveTextureARB");
1713 /* Generate an opengl texture name */
1714 glGenTextures(1, &This->dummyTextureName[i]);
1715 checkGLcall("glGenTextures");
1716 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1718 /* Generate a dummy 2d texture (not using 1d because they cause many
1719 * DRI drivers fall back to sw) */
1720 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1721 checkGLcall("glBindTexture");
1723 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1724 checkGLcall("glTexImage2D");
1727 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1729 /* Reenable because if supported it is enabled by default */
1730 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1731 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1734 LEAVE_GL();
1737 /* Context activation is done by the caller. */
1738 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1740 ENTER_GL();
1741 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1742 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1743 LEAVE_GL();
1745 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1748 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1750 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1752 if (!wined3d_register_window(window, device))
1754 ERR("Failed to register window %p.\n", window);
1755 return E_FAIL;
1758 device->focus_window = window;
1759 SetForegroundWindow(window);
1761 return WINED3D_OK;
1764 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1766 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1768 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1769 device->focus_window = NULL;
1772 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1773 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1776 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1777 IWineD3DSwapChainImpl *swapchain = NULL;
1778 struct wined3d_context *context;
1779 HRESULT hr;
1780 DWORD state;
1781 unsigned int i;
1783 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1785 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1786 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1788 TRACE("(%p) : Creating stateblock\n", This);
1789 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1790 if (FAILED(hr))
1792 WARN("Failed to create stateblock\n");
1793 goto err_out;
1795 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1796 This->updateStateBlock = This->stateBlock;
1797 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1799 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1800 sizeof(*This->render_targets) * gl_info->limits.buffers);
1802 This->NumberOfPalettes = 1;
1803 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1804 if (!This->palettes || !This->render_targets)
1806 ERR("Out of memory!\n");
1807 hr = E_OUTOFMEMORY;
1808 goto err_out;
1810 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1811 if(!This->palettes[0]) {
1812 ERR("Out of memory!\n");
1813 hr = E_OUTOFMEMORY;
1814 goto err_out;
1816 for (i = 0; i < 256; ++i) {
1817 This->palettes[0][i].peRed = 0xFF;
1818 This->palettes[0][i].peGreen = 0xFF;
1819 This->palettes[0][i].peBlue = 0xFF;
1820 This->palettes[0][i].peFlags = 0xFF;
1822 This->currentPalette = 0;
1824 /* Initialize the texture unit mapping to a 1:1 mapping */
1825 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1827 if (state < gl_info->limits.fragment_samplers)
1829 This->texUnitMap[state] = state;
1830 This->rev_tex_unit_map[state] = state;
1831 } else {
1832 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1833 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1837 /* Setup the implicit swapchain. This also initializes a context. */
1838 TRACE("Creating implicit swapchain\n");
1839 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1840 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1841 if (FAILED(hr))
1843 WARN("Failed to create implicit swapchain\n");
1844 goto err_out;
1847 This->NumberOfSwapChains = 1;
1848 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1849 if(!This->swapchains) {
1850 ERR("Out of memory!\n");
1851 goto err_out;
1853 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1855 if (swapchain->back_buffers && swapchain->back_buffers[0])
1857 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1858 This->render_targets[0] = swapchain->back_buffers[0];
1860 else
1862 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1863 This->render_targets[0] = swapchain->front_buffer;
1865 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1867 /* Depth Stencil support */
1868 This->depth_stencil = This->auto_depth_stencil;
1869 if (This->depth_stencil)
1870 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1872 hr = This->shader_backend->shader_alloc_private(iface);
1873 if(FAILED(hr)) {
1874 TRACE("Shader private data couldn't be allocated\n");
1875 goto err_out;
1877 hr = This->frag_pipe->alloc_private(iface);
1878 if(FAILED(hr)) {
1879 TRACE("Fragment pipeline private data couldn't be allocated\n");
1880 goto err_out;
1882 hr = This->blitter->alloc_private(iface);
1883 if(FAILED(hr)) {
1884 TRACE("Blitter private data couldn't be allocated\n");
1885 goto err_out;
1888 /* Set up some starting GL setup */
1890 /* Setup all the devices defaults */
1891 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1893 context = context_acquire(This, swapchain->front_buffer);
1895 create_dummy_textures(This);
1897 ENTER_GL();
1899 /* Initialize the current view state */
1900 This->view_ident = 1;
1901 This->contexts[0]->last_was_rhw = 0;
1902 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1903 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1905 switch(wined3d_settings.offscreen_rendering_mode) {
1906 case ORM_FBO:
1907 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1908 break;
1910 case ORM_BACKBUFFER:
1912 if (context_get_current()->aux_buffers > 0)
1914 TRACE("Using auxilliary buffer for offscreen rendering\n");
1915 This->offscreenBuffer = GL_AUX0;
1916 } else {
1917 TRACE("Using back buffer for offscreen rendering\n");
1918 This->offscreenBuffer = GL_BACK;
1923 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1924 LEAVE_GL();
1926 context_release(context);
1928 /* Clear the screen */
1929 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1930 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1931 0x00, 1.0f, 0);
1933 This->d3d_initialized = TRUE;
1935 if(wined3d_settings.logo) {
1936 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1938 This->highest_dirty_ps_const = 0;
1939 This->highest_dirty_vs_const = 0;
1940 return WINED3D_OK;
1942 err_out:
1943 HeapFree(GetProcessHeap(), 0, This->render_targets);
1944 HeapFree(GetProcessHeap(), 0, This->swapchains);
1945 This->NumberOfSwapChains = 0;
1946 if(This->palettes) {
1947 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1948 HeapFree(GetProcessHeap(), 0, This->palettes);
1950 This->NumberOfPalettes = 0;
1951 if(swapchain) {
1952 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1954 if(This->stateBlock) {
1955 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1956 This->stateBlock = NULL;
1958 if (This->blit_priv) {
1959 This->blitter->free_private(iface);
1961 if (This->fragment_priv) {
1962 This->frag_pipe->free_private(iface);
1964 if (This->shader_priv) {
1965 This->shader_backend->shader_free_private(iface);
1967 return hr;
1970 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1971 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1974 IWineD3DSwapChainImpl *swapchain = NULL;
1975 HRESULT hr;
1977 /* Setup the implicit swapchain */
1978 TRACE("Creating implicit swapchain\n");
1979 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1980 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1981 if (FAILED(hr))
1983 WARN("Failed to create implicit swapchain\n");
1984 goto err_out;
1987 This->NumberOfSwapChains = 1;
1988 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1989 if(!This->swapchains) {
1990 ERR("Out of memory!\n");
1991 goto err_out;
1993 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1994 return WINED3D_OK;
1996 err_out:
1997 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1998 return hr;
2001 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2003 IWineD3DResource_UnLoad(resource);
2004 IWineD3DResource_Release(resource);
2005 return WINED3D_OK;
2008 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2009 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2012 const struct wined3d_gl_info *gl_info;
2013 struct wined3d_context *context;
2014 int sampler;
2015 UINT i;
2016 TRACE("(%p)\n", This);
2018 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2020 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2021 * it was created. Thus make sure a context is active for the glDelete* calls
2023 context = context_acquire(This, NULL);
2024 gl_info = context->gl_info;
2026 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2028 /* Unload resources */
2029 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2031 TRACE("Deleting high order patches\n");
2032 for(i = 0; i < PATCHMAP_SIZE; i++) {
2033 struct list *e1, *e2;
2034 struct WineD3DRectPatch *patch;
2035 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2036 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2037 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2041 /* Delete the mouse cursor texture */
2042 if(This->cursorTexture) {
2043 ENTER_GL();
2044 glDeleteTextures(1, &This->cursorTexture);
2045 LEAVE_GL();
2046 This->cursorTexture = 0;
2049 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2050 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2052 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2053 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2056 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2057 * private data, it might contain opengl pointers
2059 if(This->depth_blt_texture) {
2060 ENTER_GL();
2061 glDeleteTextures(1, &This->depth_blt_texture);
2062 LEAVE_GL();
2063 This->depth_blt_texture = 0;
2065 if (This->depth_blt_rb) {
2066 ENTER_GL();
2067 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2068 LEAVE_GL();
2069 This->depth_blt_rb = 0;
2070 This->depth_blt_rb_w = 0;
2071 This->depth_blt_rb_h = 0;
2074 /* Release the update stateblock */
2075 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2076 if(This->updateStateBlock != This->stateBlock)
2077 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2079 This->updateStateBlock = NULL;
2081 { /* because were not doing proper internal refcounts releasing the primary state block
2082 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2083 to set this->stateBlock = NULL; first */
2084 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2085 This->stateBlock = NULL;
2087 /* Release the stateblock */
2088 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2089 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2093 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2094 This->blitter->free_private(iface);
2095 This->frag_pipe->free_private(iface);
2096 This->shader_backend->shader_free_private(iface);
2098 /* Release the buffers (with sanity checks)*/
2099 if (This->onscreen_depth_stencil)
2101 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2102 This->onscreen_depth_stencil = NULL;
2105 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2106 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2108 if (This->auto_depth_stencil != This->depth_stencil)
2109 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2111 This->depth_stencil = NULL;
2113 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2114 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2116 TRACE("Setting rendertarget to NULL\n");
2117 This->render_targets[0] = NULL;
2119 if (This->auto_depth_stencil)
2121 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2123 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2125 This->auto_depth_stencil = NULL;
2128 context_release(context);
2130 for(i=0; i < This->NumberOfSwapChains; i++) {
2131 TRACE("Releasing the implicit swapchain %d\n", i);
2132 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2133 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2137 HeapFree(GetProcessHeap(), 0, This->swapchains);
2138 This->swapchains = NULL;
2139 This->NumberOfSwapChains = 0;
2141 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2142 HeapFree(GetProcessHeap(), 0, This->palettes);
2143 This->palettes = NULL;
2144 This->NumberOfPalettes = 0;
2146 HeapFree(GetProcessHeap(), 0, This->render_targets);
2147 This->render_targets = NULL;
2149 This->d3d_initialized = FALSE;
2151 return WINED3D_OK;
2154 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2156 unsigned int i;
2158 for(i=0; i < This->NumberOfSwapChains; i++) {
2159 TRACE("Releasing the implicit swapchain %d\n", i);
2160 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2161 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2165 HeapFree(GetProcessHeap(), 0, This->swapchains);
2166 This->swapchains = NULL;
2167 This->NumberOfSwapChains = 0;
2168 return WINED3D_OK;
2171 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2172 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2173 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2175 * There is no way to deactivate thread safety once it is enabled.
2177 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2180 /*For now just store the flag(needed in case of ddraw) */
2181 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2184 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2185 const WINED3DDISPLAYMODE* pMode) {
2186 DEVMODEW devmode;
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2188 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2189 LONG ret;
2190 RECT clip_rc;
2192 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2194 /* Resize the screen even without a window:
2195 * The app could have unset it with SetCooperativeLevel, but not called
2196 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2197 * but we don't have any hwnd
2200 memset(&devmode, 0, sizeof(devmode));
2201 devmode.dmSize = sizeof(devmode);
2202 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2203 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2204 devmode.dmPelsWidth = pMode->Width;
2205 devmode.dmPelsHeight = pMode->Height;
2207 devmode.dmDisplayFrequency = pMode->RefreshRate;
2208 if (pMode->RefreshRate)
2209 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2211 /* Only change the mode if necessary */
2212 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2213 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2214 return WINED3D_OK;
2216 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2217 if (ret != DISP_CHANGE_SUCCESSFUL)
2219 if (devmode.dmDisplayFrequency)
2221 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2222 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2223 devmode.dmDisplayFrequency = 0;
2224 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2226 if(ret != DISP_CHANGE_SUCCESSFUL) {
2227 return WINED3DERR_NOTAVAILABLE;
2231 /* Store the new values */
2232 This->ddraw_width = pMode->Width;
2233 This->ddraw_height = pMode->Height;
2234 This->ddraw_format = pMode->Format;
2236 /* And finally clip mouse to our screen */
2237 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2238 ClipCursor(&clip_rc);
2240 return WINED3D_OK;
2243 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 *ppD3D = This->wined3d;
2246 TRACE("Returning %p.\n", *ppD3D);
2247 IWineD3D_AddRef(*ppD3D);
2248 return WINED3D_OK;
2251 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2254 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2255 (This->adapter->TextureRam/(1024*1024)),
2256 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2257 /* return simulated texture memory left */
2258 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2261 /*****
2262 * Get / Set Stream Source
2263 *****/
2264 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2265 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 struct wined3d_stream_state *stream;
2269 IWineD3DBuffer *oldSrc;
2271 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2272 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2274 if (StreamNumber >= MAX_STREAMS) {
2275 WARN("Stream out of range %d\n", StreamNumber);
2276 return WINED3DERR_INVALIDCALL;
2277 } else if(OffsetInBytes & 0x3) {
2278 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2279 return WINED3DERR_INVALIDCALL;
2282 stream = &This->updateStateBlock->state.streams[StreamNumber];
2283 oldSrc = (IWineD3DBuffer *)stream->buffer;
2285 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2287 if (oldSrc == pStreamData
2288 && stream->stride == Stride
2289 && stream->offset == OffsetInBytes)
2291 TRACE("Application is setting the old values over, nothing to do\n");
2292 return WINED3D_OK;
2295 stream->buffer = (struct wined3d_buffer *)pStreamData;
2296 if (pStreamData)
2298 stream->stride = Stride;
2299 stream->offset = OffsetInBytes;
2302 /* Handle recording of state blocks */
2303 if (This->isRecordingState) {
2304 TRACE("Recording... not performing anything\n");
2305 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2306 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2307 return WINED3D_OK;
2310 if (pStreamData)
2312 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2313 IWineD3DBuffer_AddRef(pStreamData);
2315 if (oldSrc)
2317 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2318 IWineD3DBuffer_Release(oldSrc);
2321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2323 return WINED3D_OK;
2326 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2327 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 struct wined3d_stream_state *stream;
2332 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2333 iface, StreamNumber, pStream, pOffset, pStride);
2335 if (StreamNumber >= MAX_STREAMS)
2337 WARN("Stream out of range %d\n", StreamNumber);
2338 return WINED3DERR_INVALIDCALL;
2341 stream = &This->stateBlock->state.streams[StreamNumber];
2342 *pStream = (IWineD3DBuffer *)stream->buffer;
2343 *pStride = stream->stride;
2344 if (pOffset) *pOffset = stream->offset;
2346 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2348 return WINED3D_OK;
2351 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 struct wined3d_stream_state *stream;
2354 UINT oldFlags, oldFreq;
2356 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2358 /* Verify input at least in d3d9 this is invalid. */
2359 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2361 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2362 return WINED3DERR_INVALIDCALL;
2364 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2366 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2367 return WINED3DERR_INVALIDCALL;
2369 if (!Divider)
2371 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2372 return WINED3DERR_INVALIDCALL;
2375 stream = &This->updateStateBlock->state.streams[StreamNumber];
2376 oldFlags = stream->flags;
2377 oldFreq = stream->frequency;
2379 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2380 stream->frequency = Divider & 0x7FFFFF;
2382 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2384 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2387 return WINED3D_OK;
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 struct wined3d_stream_state *stream;
2394 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2396 stream = &This->updateStateBlock->state.streams[StreamNumber];
2397 *Divider = stream->flags | stream->frequency;
2399 TRACE("Returning %#x.\n", *Divider);
2401 return WINED3D_OK;
2404 /*****
2405 * Get / Set & Multiply Transform
2406 *****/
2407 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2410 /* Most of this routine, comments included copied from ddraw tree initially: */
2411 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2413 /* Handle recording of state blocks */
2414 if (This->isRecordingState) {
2415 TRACE("Recording... not performing anything\n");
2416 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2417 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2418 return WINED3D_OK;
2422 * If the new matrix is the same as the current one,
2423 * we cut off any further processing. this seems to be a reasonable
2424 * optimization because as was noticed, some apps (warcraft3 for example)
2425 * tend towards setting the same matrix repeatedly for some reason.
2427 * From here on we assume that the new matrix is different, wherever it matters.
2429 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2431 TRACE("The app is setting the same matrix over again\n");
2432 return WINED3D_OK;
2434 else
2436 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2440 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2441 where ViewMat = Camera space, WorldMat = world space.
2443 In OpenGL, camera and world space is combined into GL_MODELVIEW
2444 matrix. The Projection matrix stay projection matrix.
2447 /* Capture the times we can just ignore the change for now */
2448 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2449 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2450 /* Handled by the state manager */
2453 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2456 return WINED3D_OK;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2461 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2463 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2465 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2467 *matrix = device->stateBlock->state.transforms[state];
2469 return WINED3D_OK;
2472 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2473 const WINED3DMATRIX *mat = NULL;
2474 WINED3DMATRIX temp;
2476 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2477 * below means it will be recorded in a state block change, but it
2478 * works regardless where it is recorded.
2479 * If this is found to be wrong, change to StateBlock.
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2484 if (State <= HIGHEST_TRANSFORMSTATE)
2486 mat = &This->updateStateBlock->state.transforms[State];
2488 else
2490 FIXME("Unhandled transform state!!\n");
2493 multiply_matrix(&temp, mat, pMatrix);
2495 /* Apply change via set transform - will reapply to eg. lights this way */
2496 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2499 /*****
2500 * Get / Set Light
2501 *****/
2502 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2503 you can reference any indexes you want as long as that number max are enabled at any
2504 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2505 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2506 but when recording, just build a chain pretty much of commands to be replayed. */
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2509 float rho;
2510 struct wined3d_light_info *object = NULL;
2511 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2512 struct list *e;
2514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2515 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2517 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2518 * the gl driver.
2520 if(!pLight) {
2521 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2522 return WINED3DERR_INVALIDCALL;
2525 switch(pLight->Type) {
2526 case WINED3DLIGHT_POINT:
2527 case WINED3DLIGHT_SPOT:
2528 case WINED3DLIGHT_PARALLELPOINT:
2529 case WINED3DLIGHT_GLSPOT:
2530 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2531 * most wanted
2533 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2535 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2536 return WINED3DERR_INVALIDCALL;
2538 break;
2540 case WINED3DLIGHT_DIRECTIONAL:
2541 /* Ignores attenuation */
2542 break;
2544 default:
2545 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2546 return WINED3DERR_INVALIDCALL;
2549 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2551 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2552 if(object->OriginalIndex == Index) break;
2553 object = NULL;
2556 if(!object) {
2557 TRACE("Adding new light\n");
2558 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2559 if(!object) {
2560 ERR("Out of memory error when allocating a light\n");
2561 return E_OUTOFMEMORY;
2563 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2564 object->glIndex = -1;
2565 object->OriginalIndex = Index;
2568 /* Initialize the object */
2569 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,
2570 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2571 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2572 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2573 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2574 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2575 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2577 /* Save away the information */
2578 object->OriginalParms = *pLight;
2580 switch (pLight->Type) {
2581 case WINED3DLIGHT_POINT:
2582 /* Position */
2583 object->lightPosn[0] = pLight->Position.x;
2584 object->lightPosn[1] = pLight->Position.y;
2585 object->lightPosn[2] = pLight->Position.z;
2586 object->lightPosn[3] = 1.0f;
2587 object->cutoff = 180.0f;
2588 /* FIXME: Range */
2589 break;
2591 case WINED3DLIGHT_DIRECTIONAL:
2592 /* Direction */
2593 object->lightPosn[0] = -pLight->Direction.x;
2594 object->lightPosn[1] = -pLight->Direction.y;
2595 object->lightPosn[2] = -pLight->Direction.z;
2596 object->lightPosn[3] = 0.0f;
2597 object->exponent = 0.0f;
2598 object->cutoff = 180.0f;
2599 break;
2601 case WINED3DLIGHT_SPOT:
2602 /* Position */
2603 object->lightPosn[0] = pLight->Position.x;
2604 object->lightPosn[1] = pLight->Position.y;
2605 object->lightPosn[2] = pLight->Position.z;
2606 object->lightPosn[3] = 1.0f;
2608 /* Direction */
2609 object->lightDirn[0] = pLight->Direction.x;
2610 object->lightDirn[1] = pLight->Direction.y;
2611 object->lightDirn[2] = pLight->Direction.z;
2612 object->lightDirn[3] = 1.0f;
2615 * opengl-ish and d3d-ish spot lights use too different models for the
2616 * light "intensity" as a function of the angle towards the main light direction,
2617 * so we only can approximate very roughly.
2618 * however spot lights are rather rarely used in games (if ever used at all).
2619 * furthermore if still used, probably nobody pays attention to such details.
2621 if (!pLight->Falloff)
2623 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2624 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2625 * will always be 1.0 for both of them, and we don't have to care for the
2626 * rest of the rather complex calculation
2628 object->exponent = 0.0f;
2629 } else {
2630 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2631 if (rho < 0.0001f) rho = 0.0001f;
2632 object->exponent = -0.3f/logf(cosf(rho/2));
2634 if (object->exponent > 128.0f)
2636 object->exponent = 128.0f;
2638 object->cutoff = (float) (pLight->Phi*90/M_PI);
2640 /* FIXME: Range */
2641 break;
2643 default:
2644 FIXME("Unrecognized light type %d\n", pLight->Type);
2647 /* Update the live definitions if the light is currently assigned a glIndex */
2648 if (object->glIndex != -1 && !This->isRecordingState) {
2649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2651 return WINED3D_OK;
2654 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2656 struct wined3d_light_info *lightInfo = NULL;
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2659 struct list *e;
2660 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2662 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2664 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2665 if(lightInfo->OriginalIndex == Index) break;
2666 lightInfo = NULL;
2669 if (!lightInfo)
2671 TRACE("Light information requested but light not defined\n");
2672 return WINED3DERR_INVALIDCALL;
2675 *pLight = lightInfo->OriginalParms;
2676 return WINED3D_OK;
2679 /*****
2680 * Get / Set Light Enable
2681 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2682 *****/
2683 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2685 struct wined3d_light_info *lightInfo = NULL;
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2688 struct list *e;
2689 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2691 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2693 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2694 if(lightInfo->OriginalIndex == Index) break;
2695 lightInfo = NULL;
2697 TRACE("Found light: %p\n", lightInfo);
2699 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2700 if (!lightInfo)
2702 TRACE("Light enabled requested but light not defined, so defining one!\n");
2703 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2705 /* Search for it again! Should be fairly quick as near head of list */
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 if (!lightInfo)
2714 FIXME("Adding default lights has failed dismally\n");
2715 return WINED3DERR_INVALIDCALL;
2719 if(!Enable) {
2720 if(lightInfo->glIndex != -1) {
2721 if(!This->isRecordingState) {
2722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2725 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2726 lightInfo->glIndex = -1;
2727 } else {
2728 TRACE("Light already disabled, nothing to do\n");
2730 lightInfo->enabled = FALSE;
2731 } else {
2732 lightInfo->enabled = TRUE;
2733 if (lightInfo->glIndex != -1) {
2734 /* nop */
2735 TRACE("Nothing to do as light was enabled\n");
2736 } else {
2737 int i;
2738 /* Find a free gl light */
2739 for (i = 0; i < This->maxConcurrentLights; ++i)
2741 if (!This->updateStateBlock->state.lights[i])
2743 This->updateStateBlock->state.lights[i] = lightInfo;
2744 lightInfo->glIndex = i;
2745 break;
2748 if(lightInfo->glIndex == -1) {
2749 /* Our tests show that Windows returns D3D_OK in this situation, even with
2750 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2751 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2752 * as well for those lights.
2754 * TODO: Test how this affects rendering
2756 WARN("Too many concurrently active lights\n");
2757 return WINED3D_OK;
2760 /* i == lightInfo->glIndex */
2761 if(!This->isRecordingState) {
2762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2767 return WINED3D_OK;
2770 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2772 struct wined3d_light_info *lightInfo = NULL;
2773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2774 struct list *e;
2775 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2776 TRACE("(%p) : for idx(%d)\n", This, Index);
2778 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2780 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2781 if(lightInfo->OriginalIndex == Index) break;
2782 lightInfo = NULL;
2785 if (!lightInfo)
2787 TRACE("Light enabled state requested but light not defined\n");
2788 return WINED3DERR_INVALIDCALL;
2790 /* true is 128 according to SetLightEnable */
2791 *pEnable = lightInfo->enabled ? 128 : 0;
2792 return WINED3D_OK;
2795 /*****
2796 * Get / Set Clip Planes
2797 *****/
2798 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2802 /* Validate Index */
2803 if (Index >= This->adapter->gl_info.limits.clipplanes)
2805 TRACE("Application has requested clipplane this device doesn't support\n");
2806 return WINED3DERR_INVALIDCALL;
2809 This->updateStateBlock->changed.clipplane |= 1 << Index;
2811 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2812 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2813 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2814 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2816 TRACE("Application is setting old values over, nothing to do\n");
2817 return WINED3D_OK;
2820 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2821 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2822 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2823 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2825 /* Handle recording of state blocks */
2826 if (This->isRecordingState) {
2827 TRACE("Recording... not performing anything\n");
2828 return WINED3D_OK;
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2833 return WINED3D_OK;
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 TRACE("(%p) : for idx %d\n", This, Index);
2840 /* Validate Index */
2841 if (Index >= This->adapter->gl_info.limits.clipplanes)
2843 TRACE("Application has requested clipplane this device doesn't support\n");
2844 return WINED3DERR_INVALIDCALL;
2847 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2848 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2849 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2850 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2851 return WINED3D_OK;
2854 /*****
2855 * Get / Set Clip Plane Status
2856 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2857 *****/
2858 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 FIXME("(%p) : stub\n", This);
2862 if (!pClipStatus)
2863 return WINED3DERR_INVALIDCALL;
2865 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2866 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2867 return WINED3D_OK;
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 FIXME("(%p) : stub\n", This);
2874 if (!pClipStatus)
2875 return WINED3DERR_INVALIDCALL;
2877 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2878 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2879 return WINED3D_OK;
2882 /*****
2883 * Get / Set Material
2884 *****/
2885 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 This->updateStateBlock->changed.material = TRUE;
2889 This->updateStateBlock->state.material = *pMaterial;
2891 /* Handle recording of state blocks */
2892 if (This->isRecordingState) {
2893 TRACE("Recording... not performing anything\n");
2894 return WINED3D_OK;
2897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 *pMaterial = This->updateStateBlock->state.material;
2904 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2905 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2906 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2907 pMaterial->Ambient.b, pMaterial->Ambient.a);
2908 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2909 pMaterial->Specular.b, pMaterial->Specular.a);
2910 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2911 pMaterial->Emissive.b, pMaterial->Emissive.a);
2912 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2914 return WINED3D_OK;
2917 /*****
2918 * Get / Set Indices
2919 *****/
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2921 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 IWineD3DBuffer *oldIdxs;
2926 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2927 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2929 This->updateStateBlock->changed.indices = TRUE;
2930 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2931 This->updateStateBlock->state.index_format = fmt;
2933 /* Handle recording of state blocks */
2934 if (This->isRecordingState) {
2935 TRACE("Recording... not performing anything\n");
2936 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2937 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2938 return WINED3D_OK;
2941 if(oldIdxs != pIndexData) {
2942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2943 if(pIndexData) {
2944 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2945 IWineD3DBuffer_AddRef(pIndexData);
2947 if(oldIdxs) {
2948 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2949 IWineD3DBuffer_Release(oldIdxs);
2953 return WINED3D_OK;
2956 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2962 /* up ref count on ppindexdata */
2963 if (*ppIndexData) {
2964 IWineD3DBuffer_AddRef(*ppIndexData);
2965 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2966 }else{
2967 TRACE("(%p) No index data set\n", This);
2969 TRACE("Returning %p\n", *ppIndexData);
2971 return WINED3D_OK;
2974 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2975 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 TRACE("(%p)->(%d)\n", This, BaseIndex);
2979 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2981 TRACE("Application is setting the old value over, nothing to do\n");
2982 return WINED3D_OK;
2985 This->updateStateBlock->state.base_vertex_index = BaseIndex;
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2989 return WINED3D_OK;
2991 /* The base vertex index affects the stream sources */
2992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2993 return WINED3D_OK;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 TRACE("(%p) : base_index %p\n", This, base_index);
3000 *base_index = This->stateBlock->state.base_vertex_index;
3002 TRACE("Returning %u\n", *base_index);
3004 return WINED3D_OK;
3007 /*****
3008 * Get / Set Viewports
3009 *****/
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p)\n", This);
3014 This->updateStateBlock->changed.viewport = TRUE;
3015 This->updateStateBlock->state.viewport = *pViewport;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3020 return WINED3D_OK;
3023 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3024 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3027 return WINED3D_OK;
3031 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p)\n", This);
3034 *pViewport = This->stateBlock->state.viewport;
3035 return WINED3D_OK;
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3039 WINED3DRENDERSTATETYPE State, DWORD Value)
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 DWORD oldValue = This->stateBlock->state.render_states[State];
3044 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3046 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3047 This->updateStateBlock->state.render_states[State] = Value;
3049 /* Handle recording of state blocks */
3050 if (This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3052 return WINED3D_OK;
3055 /* Compared here and not before the assignment to allow proper stateblock recording */
3056 if(Value == oldValue) {
3057 TRACE("Application is setting the old value over, nothing to do\n");
3058 } else {
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3062 return WINED3D_OK;
3065 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3066 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3072 *pValue = This->stateBlock->state.render_states[State];
3073 return WINED3D_OK;
3076 /*****
3077 * Get / Set Sampler States
3078 * TODO: Verify against dx9 definitions
3079 *****/
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 DWORD oldValue;
3085 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3086 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3088 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3089 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3092 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3094 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3095 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3098 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3099 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3100 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3102 /* Handle recording of state blocks */
3103 if (This->isRecordingState) {
3104 TRACE("Recording... not performing anything\n");
3105 return WINED3D_OK;
3108 if(oldValue == Value) {
3109 TRACE("Application is setting the old value over, nothing to do\n");
3110 return WINED3D_OK;
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3115 return WINED3D_OK;
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3122 This, Sampler, debug_d3dsamplerstate(Type), Type);
3124 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3125 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3128 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3130 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3131 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3133 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3134 TRACE("(%p) : Returning %#x\n", This, *Value);
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 This->updateStateBlock->changed.scissorRect = TRUE;
3143 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3145 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3146 return WINED3D_OK;
3148 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3150 if(This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3152 return WINED3D_OK;
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 *pRect = This->updateStateBlock->state.scissor_rect;
3164 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3165 return WINED3D_OK;
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3170 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3172 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3174 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3175 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3177 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3178 This->updateStateBlock->changed.vertexDecl = TRUE;
3180 if (This->isRecordingState) {
3181 TRACE("Recording... not performing anything\n");
3182 return WINED3D_OK;
3183 } else if(pDecl == oldDecl) {
3184 /* Checked after the assignment to allow proper stateblock recording */
3185 TRACE("Application is setting the old declaration over, nothing to do\n");
3186 return WINED3D_OK;
3189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3190 return WINED3D_OK;
3193 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3196 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3198 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3199 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3200 return WINED3D_OK;
3203 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3208 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3209 This->updateStateBlock->changed.vertexShader = TRUE;
3211 if (This->isRecordingState) {
3212 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3213 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3214 TRACE("Recording... not performing anything\n");
3215 return WINED3D_OK;
3216 } else if(oldShader == pShader) {
3217 /* Checked here to allow proper stateblock recording */
3218 TRACE("App is setting the old shader over, nothing to do\n");
3219 return WINED3D_OK;
3222 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3223 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3224 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3228 return WINED3D_OK;
3231 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3233 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3234 IWineD3DVertexShader *shader;
3236 TRACE("iface %p.\n", iface);
3238 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3239 if (shader) IWineD3DVertexShader_AddRef(shader);
3241 TRACE("Returning %p.\n", shader);
3242 return shader;
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3246 IWineD3DDevice *iface,
3247 UINT start,
3248 CONST BOOL *srcData,
3249 UINT count) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3254 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3255 iface, srcData, start, count);
3257 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3259 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3260 for (i = 0; i < cnt; i++)
3261 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3263 for (i = start; i < cnt + start; ++i) {
3264 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3267 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3269 return WINED3D_OK;
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3273 IWineD3DDevice *iface,
3274 UINT start,
3275 BOOL *dstData,
3276 UINT count) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 int cnt = min(count, MAX_CONST_B - start);
3281 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3282 iface, dstData, start, count);
3284 if (!dstData || cnt < 0)
3285 return WINED3DERR_INVALIDCALL;
3287 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3288 return WINED3D_OK;
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3292 IWineD3DDevice *iface,
3293 UINT start,
3294 CONST int *srcData,
3295 UINT count) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3300 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3301 iface, srcData, start, count);
3303 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3305 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3306 for (i = 0; i < cnt; i++)
3307 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3308 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3310 for (i = start; i < cnt + start; ++i) {
3311 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3314 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3316 return WINED3D_OK;
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3320 IWineD3DDevice *iface,
3321 UINT start,
3322 int *dstData,
3323 UINT count) {
3325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 int cnt = min(count, MAX_CONST_I - start);
3328 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3329 iface, dstData, start, count);
3331 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3332 return WINED3DERR_INVALIDCALL;
3334 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3335 return WINED3D_OK;
3338 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3339 IWineD3DDevice *iface,
3340 UINT start,
3341 CONST float *srcData,
3342 UINT count) {
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 UINT i;
3347 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3348 iface, srcData, start, count);
3350 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3351 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3352 return WINED3DERR_INVALIDCALL;
3354 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3355 if(TRACE_ON(d3d)) {
3356 for (i = 0; i < count; i++)
3357 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3358 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3361 if (!This->isRecordingState)
3363 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3367 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3368 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3370 return WINED3D_OK;
3373 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3374 IWineD3DDevice *iface,
3375 UINT start,
3376 float *dstData,
3377 UINT count) {
3379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 int cnt = min(count, This->d3d_vshader_constantF - start);
3382 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3383 iface, dstData, start, count);
3385 if (!dstData || cnt < 0)
3386 return WINED3DERR_INVALIDCALL;
3388 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3389 return WINED3D_OK;
3392 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3393 DWORD i;
3394 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3400 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3402 DWORD i = This->rev_tex_unit_map[unit];
3403 DWORD j = This->texUnitMap[stage];
3405 This->texUnitMap[stage] = unit;
3406 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3408 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3411 This->rev_tex_unit_map[unit] = stage;
3412 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3414 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3418 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3419 int i;
3421 This->fixed_function_usage_map = 0;
3422 for (i = 0; i < MAX_TEXTURES; ++i)
3424 const struct wined3d_state *state = &This->stateBlock->state;
3425 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3426 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3427 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3428 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3429 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3430 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3431 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3432 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3434 if (color_op == WINED3DTOP_DISABLE) {
3435 /* Not used, and disable higher stages */
3436 break;
3439 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3440 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3441 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3442 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3443 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3444 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3445 This->fixed_function_usage_map |= (1 << i);
3448 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3449 This->fixed_function_usage_map |= (1 << (i + 1));
3454 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3456 unsigned int i, tex;
3457 WORD ffu_map;
3459 device_update_fixed_function_usage_map(This);
3460 ffu_map = This->fixed_function_usage_map;
3462 if (This->max_ffp_textures == gl_info->limits.texture_stages
3463 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3465 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3467 if (!(ffu_map & 1)) continue;
3469 if (This->texUnitMap[i] != i) {
3470 device_map_stage(This, i, i);
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3472 markTextureStagesDirty(This, i);
3475 return;
3478 /* Now work out the mapping */
3479 tex = 0;
3480 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3482 if (!(ffu_map & 1)) continue;
3484 if (This->texUnitMap[i] != tex) {
3485 device_map_stage(This, i, tex);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3487 markTextureStagesDirty(This, i);
3490 ++tex;
3494 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3496 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3497 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3498 unsigned int i;
3500 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3501 if (sampler_type[i] && This->texUnitMap[i] != i)
3503 device_map_stage(This, i, i);
3504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3505 if (i < gl_info->limits.texture_stages)
3507 markTextureStagesDirty(This, i);
3513 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3514 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3516 DWORD current_mapping = This->rev_tex_unit_map[unit];
3518 /* Not currently used */
3519 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3521 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3522 /* Used by a fragment sampler */
3524 if (!pshader_sampler_tokens) {
3525 /* No pixel shader, check fixed function */
3526 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3529 /* Pixel shader, check the shader's sampler map */
3530 return !pshader_sampler_tokens[current_mapping];
3533 /* Used by a vertex sampler */
3534 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3537 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3539 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3540 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3541 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3542 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3543 int i;
3545 if (ps)
3547 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3549 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3550 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3551 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3554 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3555 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3556 if (vshader_sampler_type[i])
3558 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3560 /* Already mapped somewhere */
3561 continue;
3564 while (start >= 0) {
3565 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3567 device_map_stage(This, vsampler_idx, start);
3568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3570 --start;
3571 break;
3574 --start;
3580 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3582 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3583 BOOL vs = use_vs(This->stateBlock);
3584 BOOL ps = use_ps(This->stateBlock);
3586 * Rules are:
3587 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3588 * that would be really messy and require shader recompilation
3589 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3590 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3592 if (ps) device_map_psamplers(This, gl_info);
3593 else device_map_fixed_function_samplers(This, gl_info);
3595 if (vs) device_map_vsamplers(This, ps, gl_info);
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3601 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3602 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3603 This->updateStateBlock->changed.pixelShader = TRUE;
3605 /* Handle recording of state blocks */
3606 if (This->isRecordingState) {
3607 TRACE("Recording... not performing anything\n");
3610 if (This->isRecordingState) {
3611 TRACE("Recording... not performing anything\n");
3612 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3613 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3614 return WINED3D_OK;
3617 if(pShader == oldShader) {
3618 TRACE("App is setting the old pixel shader over, nothing to do\n");
3619 return WINED3D_OK;
3622 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3623 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3625 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3628 return WINED3D_OK;
3631 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3633 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3634 IWineD3DPixelShader *shader;
3636 TRACE("iface %p.\n", iface);
3638 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3639 if (shader) IWineD3DPixelShader_AddRef(shader);
3641 TRACE("Returning %p.\n", shader);
3642 return shader;
3645 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3646 IWineD3DDevice *iface,
3647 UINT start,
3648 CONST BOOL *srcData,
3649 UINT count) {
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3652 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3654 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3655 iface, srcData, start, count);
3657 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3659 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3660 for (i = 0; i < cnt; i++)
3661 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3663 for (i = start; i < cnt + start; ++i) {
3664 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3667 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3669 return WINED3D_OK;
3672 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3673 IWineD3DDevice *iface,
3674 UINT start,
3675 BOOL *dstData,
3676 UINT count) {
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int cnt = min(count, MAX_CONST_B - start);
3681 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3682 iface, dstData, start, count);
3684 if (!dstData || cnt < 0)
3685 return WINED3DERR_INVALIDCALL;
3687 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3688 return WINED3D_OK;
3691 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3692 IWineD3DDevice *iface,
3693 UINT start,
3694 CONST int *srcData,
3695 UINT count) {
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3700 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3701 iface, srcData, start, count);
3703 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3705 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3706 for (i = 0; i < cnt; i++)
3707 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3708 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3710 for (i = start; i < cnt + start; ++i) {
3711 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3714 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3716 return WINED3D_OK;
3719 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3720 IWineD3DDevice *iface,
3721 UINT start,
3722 int *dstData,
3723 UINT count) {
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3726 int cnt = min(count, MAX_CONST_I - start);
3728 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3729 iface, dstData, start, count);
3731 if (!dstData || cnt < 0)
3732 return WINED3DERR_INVALIDCALL;
3734 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3735 return WINED3D_OK;
3738 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3739 IWineD3DDevice *iface,
3740 UINT start,
3741 CONST float *srcData,
3742 UINT count) {
3744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3745 UINT i;
3747 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3748 iface, srcData, start, count);
3750 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3751 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3752 return WINED3DERR_INVALIDCALL;
3754 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3755 if(TRACE_ON(d3d)) {
3756 for (i = 0; i < count; i++)
3757 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3758 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3761 if (!This->isRecordingState)
3763 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3767 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3768 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3770 return WINED3D_OK;
3773 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3774 IWineD3DDevice *iface,
3775 UINT start,
3776 float *dstData,
3777 UINT count) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 int cnt = min(count, This->d3d_pshader_constantF - start);
3782 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3783 iface, dstData, start, count);
3785 if (!dstData || cnt < 0)
3786 return WINED3DERR_INVALIDCALL;
3788 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3789 return WINED3D_OK;
3792 /* Context activation is done by the caller. */
3793 /* Do not call while under the GL lock. */
3794 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3795 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3796 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3797 DWORD DestFVF)
3799 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3800 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3801 unsigned int i;
3802 WINED3DVIEWPORT vp;
3803 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3804 BOOL doClip;
3805 DWORD numTextures;
3807 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3809 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3812 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3814 ERR("Source has no position mask\n");
3815 return WINED3DERR_INVALIDCALL;
3818 if (!dest->resource.allocatedMemory)
3819 buffer_get_sysmem(dest, gl_info);
3821 /* Get a pointer into the destination vbo(create one if none exists) and
3822 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3824 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3826 dest->flags |= WINED3D_BUFFER_CREATEBO;
3827 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3830 if (dest->buffer_object)
3832 unsigned char extrabytes = 0;
3833 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3834 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3835 * this may write 4 extra bytes beyond the area that should be written
3837 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3838 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3839 if(!dest_conv_addr) {
3840 ERR("Out of memory\n");
3841 /* Continue without storing converted vertices */
3843 dest_conv = dest_conv_addr;
3846 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3848 static BOOL warned = FALSE;
3850 * The clipping code is not quite correct. Some things need
3851 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3852 * so disable clipping for now.
3853 * (The graphics in Half-Life are broken, and my processvertices
3854 * test crashes with IDirect3DDevice3)
3855 doClip = TRUE;
3857 doClip = FALSE;
3858 if(!warned) {
3859 warned = TRUE;
3860 FIXME("Clipping is broken and disabled for now\n");
3862 } else doClip = FALSE;
3863 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3865 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3866 WINED3DTS_VIEW,
3867 &view_mat);
3868 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3869 WINED3DTS_PROJECTION,
3870 &proj_mat);
3871 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3872 WINED3DTS_WORLDMATRIX(0),
3873 &world_mat);
3875 TRACE("View mat:\n");
3876 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);
3877 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);
3878 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);
3879 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);
3881 TRACE("Proj mat:\n");
3882 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);
3883 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);
3884 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);
3885 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);
3887 TRACE("World mat:\n");
3888 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);
3889 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);
3890 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);
3891 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);
3893 /* Get the viewport */
3894 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3895 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3896 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3898 multiply_matrix(&mat,&view_mat,&world_mat);
3899 multiply_matrix(&mat,&proj_mat,&mat);
3901 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3903 for (i = 0; i < dwCount; i+= 1) {
3904 unsigned int tex_index;
3906 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3907 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3908 /* The position first */
3909 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3910 const float *p = (const float *)(element->data + i * element->stride);
3911 float x, y, z, rhw;
3912 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3914 /* Multiplication with world, view and projection matrix */
3915 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);
3916 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);
3917 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);
3918 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);
3920 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3922 /* WARNING: The following things are taken from d3d7 and were not yet checked
3923 * against d3d8 or d3d9!
3926 /* Clipping conditions: From msdn
3928 * A vertex is clipped if it does not match the following requirements
3929 * -rhw < x <= rhw
3930 * -rhw < y <= rhw
3931 * 0 < z <= rhw
3932 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3934 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3935 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3939 if( !doClip ||
3940 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3941 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3942 ( rhw > eps ) ) ) {
3944 /* "Normal" viewport transformation (not clipped)
3945 * 1) The values are divided by rhw
3946 * 2) The y axis is negative, so multiply it with -1
3947 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3948 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3949 * 4) Multiply x with Width/2 and add Width/2
3950 * 5) The same for the height
3951 * 6) Add the viewpoint X and Y to the 2D coordinates and
3952 * The minimum Z value to z
3953 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3955 * Well, basically it's simply a linear transformation into viewport
3956 * coordinates
3959 x /= rhw;
3960 y /= rhw;
3961 z /= rhw;
3963 y *= -1;
3965 x *= vp.Width / 2;
3966 y *= vp.Height / 2;
3967 z *= vp.MaxZ - vp.MinZ;
3969 x += vp.Width / 2 + vp.X;
3970 y += vp.Height / 2 + vp.Y;
3971 z += vp.MinZ;
3973 rhw = 1 / rhw;
3974 } else {
3975 /* That vertex got clipped
3976 * Contrary to OpenGL it is not dropped completely, it just
3977 * undergoes a different calculation.
3979 TRACE("Vertex got clipped\n");
3980 x += rhw;
3981 y += rhw;
3983 x /= 2;
3984 y /= 2;
3986 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3987 * outside of the main vertex buffer memory. That needs some more
3988 * investigation...
3992 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3995 ( (float *) dest_ptr)[0] = x;
3996 ( (float *) dest_ptr)[1] = y;
3997 ( (float *) dest_ptr)[2] = z;
3998 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4000 dest_ptr += 3 * sizeof(float);
4002 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4003 dest_ptr += sizeof(float);
4006 if(dest_conv) {
4007 float w = 1 / rhw;
4008 ( (float *) dest_conv)[0] = x * w;
4009 ( (float *) dest_conv)[1] = y * w;
4010 ( (float *) dest_conv)[2] = z * w;
4011 ( (float *) dest_conv)[3] = w;
4013 dest_conv += 3 * sizeof(float);
4015 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4016 dest_conv += sizeof(float);
4020 if (DestFVF & WINED3DFVF_PSIZE) {
4021 dest_ptr += sizeof(DWORD);
4022 if(dest_conv) dest_conv += sizeof(DWORD);
4024 if (DestFVF & WINED3DFVF_NORMAL) {
4025 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4026 const float *normal = (const float *)(element->data + i * element->stride);
4027 /* AFAIK this should go into the lighting information */
4028 FIXME("Didn't expect the destination to have a normal\n");
4029 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4030 if(dest_conv) {
4031 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4035 if (DestFVF & WINED3DFVF_DIFFUSE) {
4036 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4037 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4038 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4040 static BOOL warned = FALSE;
4042 if(!warned) {
4043 ERR("No diffuse color in source, but destination has one\n");
4044 warned = TRUE;
4047 *( (DWORD *) dest_ptr) = 0xffffffff;
4048 dest_ptr += sizeof(DWORD);
4050 if(dest_conv) {
4051 *( (DWORD *) dest_conv) = 0xffffffff;
4052 dest_conv += sizeof(DWORD);
4055 else {
4056 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4057 if(dest_conv) {
4058 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4059 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4060 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4061 dest_conv += sizeof(DWORD);
4066 if (DestFVF & WINED3DFVF_SPECULAR)
4068 /* What's the color value in the feedback buffer? */
4069 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4070 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4071 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4073 static BOOL warned = FALSE;
4075 if(!warned) {
4076 ERR("No specular color in source, but destination has one\n");
4077 warned = TRUE;
4080 *( (DWORD *) dest_ptr) = 0xFF000000;
4081 dest_ptr += sizeof(DWORD);
4083 if(dest_conv) {
4084 *( (DWORD *) dest_conv) = 0xFF000000;
4085 dest_conv += sizeof(DWORD);
4088 else {
4089 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4090 if(dest_conv) {
4091 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4092 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4093 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4094 dest_conv += sizeof(DWORD);
4099 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4100 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4101 const float *tex_coord = (const float *)(element->data + i * element->stride);
4102 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4104 ERR("No source texture, but destination requests one\n");
4105 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4106 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4108 else {
4109 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4110 if(dest_conv) {
4111 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4117 if (dest_conv)
4119 ENTER_GL();
4121 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4122 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4123 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4124 dwCount * get_flexible_vertex_size(DestFVF),
4125 dest_conv_addr));
4126 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4128 LEAVE_GL();
4130 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4133 return WINED3D_OK;
4135 #undef copy_and_next
4137 /* Do not call while under the GL lock. */
4138 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4139 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4140 DWORD DestFVF)
4142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4143 struct wined3d_stream_info stream_info;
4144 const struct wined3d_gl_info *gl_info;
4145 struct wined3d_context *context;
4146 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4147 HRESULT hr;
4149 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4151 if(pVertexDecl) {
4152 ERR("Output vertex declaration not implemented yet\n");
4155 /* Need any context to write to the vbo. */
4156 context = context_acquire(This, NULL);
4157 gl_info = context->gl_info;
4159 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4160 * control the streamIsUP flag, thus restore it afterwards.
4162 This->stateBlock->state.user_stream = FALSE;
4163 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4164 This->stateBlock->state.user_stream = streamWasUP;
4166 if(vbo || SrcStartIndex) {
4167 unsigned int i;
4168 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4169 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4171 * Also get the start index in, but only loop over all elements if there's something to add at all.
4173 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4175 struct wined3d_stream_info_element *e;
4177 if (!(stream_info.use_map & (1 << i))) continue;
4179 e = &stream_info.elements[i];
4180 if (e->buffer_object)
4182 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4183 e->buffer_object = 0;
4184 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4185 ENTER_GL();
4186 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4187 vb->buffer_object = 0;
4188 LEAVE_GL();
4190 if (e->data) e->data += e->stride * SrcStartIndex;
4194 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4195 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4197 context_release(context);
4199 return hr;
4202 /*****
4203 * Get / Set Texture Stage States
4204 * TODO: Verify against dx9 definitions
4205 *****/
4206 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4209 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4210 DWORD oldValue;
4212 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4214 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4216 WARN("Invalid Type %d passed.\n", Type);
4217 return WINED3D_OK;
4220 if (Stage >= gl_info->limits.texture_stages)
4222 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4223 Stage, gl_info->limits.texture_stages - 1);
4224 return WINED3D_OK;
4227 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4228 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4229 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4231 if (This->isRecordingState) {
4232 TRACE("Recording... not performing anything\n");
4233 return WINED3D_OK;
4236 /* Checked after the assignments to allow proper stateblock recording */
4237 if(oldValue == Value) {
4238 TRACE("App is setting the old value over, nothing to do\n");
4239 return WINED3D_OK;
4242 if (Stage > This->stateBlock->state.lowest_disabled_stage
4243 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4244 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4246 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4247 * Changes in other states are important on disabled stages too
4249 return WINED3D_OK;
4252 if(Type == WINED3DTSS_COLOROP) {
4253 unsigned int i;
4255 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4256 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4257 * they have to be disabled
4259 * The current stage is dirtified below.
4261 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4263 TRACE("Additionally dirtifying stage %u\n", i);
4264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4266 This->stateBlock->state.lowest_disabled_stage = Stage;
4267 TRACE("New lowest disabled: %u\n", Stage);
4268 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4269 /* Previously disabled stage enabled. Stages above it may need enabling
4270 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4271 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4273 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4276 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4278 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4279 break;
4280 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4283 This->stateBlock->state.lowest_disabled_stage = i;
4284 TRACE("New lowest disabled: %u\n", i);
4288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4290 return WINED3D_OK;
4293 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4297 TRACE("iface %p, stage %u, state %s, value %p.\n",
4298 iface, Stage, debug_d3dtexturestate(Type), pValue);
4300 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4302 WARN("Invalid Type %d passed.\n", Type);
4303 return WINED3D_OK;
4306 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4307 TRACE("Returning %#x.\n", *pValue);
4309 return WINED3D_OK;
4312 /*****
4313 * Get / Set Texture
4314 *****/
4315 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4316 DWORD stage, IWineD3DBaseTexture *texture)
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4320 IWineD3DBaseTexture *prev;
4322 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4324 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4325 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4327 /* Windows accepts overflowing this array... we do not. */
4328 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4330 WARN("Ignoring invalid stage %u.\n", stage);
4331 return WINED3D_OK;
4334 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4335 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4337 WARN("Rejecting attempt to set scratch texture.\n");
4338 return WINED3DERR_INVALIDCALL;
4341 This->updateStateBlock->changed.textures |= 1 << stage;
4343 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4344 TRACE("Previous texture %p.\n", prev);
4346 if (texture == prev)
4348 TRACE("App is setting the same texture again, nothing to do.\n");
4349 return WINED3D_OK;
4352 TRACE("Setting new texture to %p.\n", texture);
4353 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4355 if (This->isRecordingState)
4357 TRACE("Recording... not performing anything\n");
4359 if (texture) IWineD3DBaseTexture_AddRef(texture);
4360 if (prev) IWineD3DBaseTexture_Release(prev);
4362 return WINED3D_OK;
4365 if (texture)
4367 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4368 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4369 GLenum dimensions = t->baseTexture.target;
4371 IWineD3DBaseTexture_AddRef(texture);
4373 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4376 if (!prev && stage < gl_info->limits.texture_stages)
4378 /* The source arguments for color and alpha ops have different
4379 * meanings when a NULL texture is bound, so the COLOROP and
4380 * ALPHAOP have to be dirtified. */
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4385 if (bind_count == 1) t->baseTexture.sampler = stage;
4388 if (prev)
4390 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4391 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4393 IWineD3DBaseTexture_Release(prev);
4395 if (!texture && stage < gl_info->limits.texture_stages)
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4401 if (bind_count && t->baseTexture.sampler == stage)
4403 unsigned int i;
4405 /* Search for other stages the texture is bound to. Shouldn't
4406 * happen if applications bind textures to a single stage only. */
4407 TRACE("Searching for other stages the texture is bound to.\n");
4408 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4410 if (This->updateStateBlock->state.textures[i] == t)
4412 TRACE("Texture is also bound to stage %u.\n", i);
4413 t->baseTexture.sampler = i;
4414 break;
4420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4422 return WINED3D_OK;
4425 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4428 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4430 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4431 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4434 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4436 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4437 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4440 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4441 if (*ppTexture)
4442 IWineD3DBaseTexture_AddRef(*ppTexture);
4444 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4446 return WINED3D_OK;
4449 /*****
4450 * Get Back Buffer
4451 *****/
4452 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4453 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4455 IWineD3DSwapChain *swapchain;
4456 HRESULT hr;
4458 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4459 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4461 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4462 if (FAILED(hr))
4464 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4465 return hr;
4468 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4469 IWineD3DSwapChain_Release(swapchain);
4470 if (FAILED(hr))
4472 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4473 return hr;
4476 return WINED3D_OK;
4479 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4481 WARN("(%p) : stub, calling idirect3d for now\n", This);
4482 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4485 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 IWineD3DSwapChain *swapChain;
4488 HRESULT hr;
4490 if(iSwapChain > 0) {
4491 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4492 if (hr == WINED3D_OK) {
4493 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4494 IWineD3DSwapChain_Release(swapChain);
4495 } else {
4496 FIXME("(%p) Error getting display mode\n", This);
4498 } else {
4499 /* Don't read the real display mode,
4500 but return the stored mode instead. X11 can't change the color
4501 depth, and some apps are pretty angry if they SetDisplayMode from
4502 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4504 Also don't relay to the swapchain because with ddraw it's possible
4505 that there isn't a swapchain at all */
4506 pMode->Width = This->ddraw_width;
4507 pMode->Height = This->ddraw_height;
4508 pMode->Format = This->ddraw_format;
4509 pMode->RefreshRate = 0;
4510 hr = WINED3D_OK;
4513 return hr;
4516 /*****
4517 * Stateblock related functions
4518 *****/
4520 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4522 IWineD3DStateBlock *stateblock;
4523 HRESULT hr;
4525 TRACE("(%p)\n", This);
4527 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4529 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4530 if (FAILED(hr)) return hr;
4532 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4533 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4534 This->isRecordingState = TRUE;
4536 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4538 return WINED3D_OK;
4541 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4545 if (!This->isRecordingState) {
4546 WARN("(%p) not recording! returning error\n", This);
4547 *ppStateBlock = NULL;
4548 return WINED3DERR_INVALIDCALL;
4551 stateblock_init_contained_states(object);
4553 *ppStateBlock = (IWineD3DStateBlock*) object;
4554 This->isRecordingState = FALSE;
4555 This->updateStateBlock = This->stateBlock;
4556 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4557 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4558 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4559 return WINED3D_OK;
4562 /*****
4563 * Scene related functions
4564 *****/
4565 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4566 /* At the moment we have no need for any functionality at the beginning
4567 of a scene */
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 TRACE("(%p)\n", This);
4571 if(This->inScene) {
4572 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4573 return WINED3DERR_INVALIDCALL;
4575 This->inScene = TRUE;
4576 return WINED3D_OK;
4579 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 struct wined3d_context *context;
4584 TRACE("(%p)\n", This);
4586 if(!This->inScene) {
4587 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4588 return WINED3DERR_INVALIDCALL;
4591 context = context_acquire(This, NULL);
4592 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4593 wglFlush();
4594 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4595 * fails. */
4596 context_release(context);
4598 This->inScene = FALSE;
4599 return WINED3D_OK;
4602 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4603 const RECT *pSourceRect, const RECT *pDestRect,
4604 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4606 IWineD3DSwapChain *swapChain = NULL;
4607 int i;
4608 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4610 TRACE("iface %p.\n", iface);
4612 for(i = 0 ; i < swapchains ; i ++) {
4614 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4615 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4616 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4617 IWineD3DSwapChain_Release(swapChain);
4620 return WINED3D_OK;
4623 /* Do not call while under the GL lock. */
4624 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4625 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4627 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4628 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4629 RECT draw_rect;
4631 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4632 iface, rect_count, rects, flags, color, depth, stencil);
4634 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4636 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4637 /* TODO: What about depth stencil buffers without stencil bits? */
4638 return WINED3DERR_INVALIDCALL;
4641 device_get_draw_rect(device, &draw_rect);
4643 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4644 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4647 /*****
4648 * Drawing functions
4649 *****/
4651 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4652 WINED3DPRIMITIVETYPE primitive_type)
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4658 This->updateStateBlock->changed.primitive_type = TRUE;
4659 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4662 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4663 WINED3DPRIMITIVETYPE *primitive_type)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4667 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4669 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4671 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4674 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4680 if (!This->stateBlock->state.vertex_declaration)
4682 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4683 return WINED3DERR_INVALIDCALL;
4686 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4687 if (This->stateBlock->state.user_stream)
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4690 This->stateBlock->state.user_stream = FALSE;
4693 if (This->stateBlock->state.load_base_vertex_index)
4695 This->stateBlock->state.load_base_vertex_index = 0;
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4698 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4699 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4700 return WINED3D_OK;
4703 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 struct wined3d_buffer *index_buffer;
4707 UINT idxStride = 2;
4708 GLuint vbo;
4710 index_buffer = This->stateBlock->state.index_buffer;
4711 if (!index_buffer)
4713 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4714 * without an index buffer set. (The first time at least...)
4715 * D3D8 simply dies, but I doubt it can do much harm to return
4716 * D3DERR_INVALIDCALL there as well. */
4717 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4718 return WINED3DERR_INVALIDCALL;
4721 if (!This->stateBlock->state.vertex_declaration)
4723 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4724 return WINED3DERR_INVALIDCALL;
4727 if (This->stateBlock->state.user_stream)
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4730 This->stateBlock->state.user_stream = FALSE;
4732 vbo = index_buffer->buffer_object;
4734 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4736 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4737 idxStride = 2;
4738 else
4739 idxStride = 4;
4741 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4743 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4747 drawPrimitive(iface, index_count, startIndex, idxStride,
4748 vbo ? NULL : index_buffer->resource.allocatedMemory);
4750 return WINED3D_OK;
4753 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4754 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 struct wined3d_stream_state *stream;
4758 IWineD3DBuffer *vb;
4760 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4761 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4763 if (!This->stateBlock->state.vertex_declaration)
4765 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4766 return WINED3DERR_INVALIDCALL;
4769 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4770 stream = &This->stateBlock->state.streams[0];
4771 vb = (IWineD3DBuffer *)stream->buffer;
4772 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4773 if (vb) IWineD3DBuffer_Release(vb);
4774 stream->offset = 0;
4775 stream->stride = VertexStreamZeroStride;
4776 This->stateBlock->state.user_stream = TRUE;
4777 This->stateBlock->state.load_base_vertex_index = 0;
4779 /* TODO: Only mark dirty if drawing from a different UP address */
4780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4782 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4784 /* MSDN specifies stream zero settings must be set to NULL */
4785 stream->buffer = NULL;
4786 stream->stride = 0;
4788 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4789 * the new stream sources or use UP drawing again
4791 return WINED3D_OK;
4794 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4795 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4796 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4798 int idxStride;
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 struct wined3d_stream_state *stream;
4801 IWineD3DBuffer *vb;
4802 IWineD3DBuffer *ib;
4804 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4805 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4807 if (!This->stateBlock->state.vertex_declaration)
4809 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4810 return WINED3DERR_INVALIDCALL;
4813 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4814 idxStride = 2;
4815 } else {
4816 idxStride = 4;
4819 stream = &This->stateBlock->state.streams[0];
4820 vb = (IWineD3DBuffer *)stream->buffer;
4821 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4822 if (vb) IWineD3DBuffer_Release(vb);
4823 stream->offset = 0;
4824 stream->stride = VertexStreamZeroStride;
4825 This->stateBlock->state.user_stream = TRUE;
4827 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4828 This->stateBlock->state.base_vertex_index = 0;
4829 This->stateBlock->state.load_base_vertex_index = 0;
4830 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4834 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4836 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4837 stream->buffer = NULL;
4838 stream->stride = 0;
4839 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4840 if (ib)
4842 IWineD3DBuffer_Release(ib);
4843 This->stateBlock->state.index_buffer = NULL;
4845 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4846 * SetStreamSource to specify a vertex buffer
4849 return WINED3D_OK;
4852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4853 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4857 /* Mark the state dirty until we have nicer tracking
4858 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4859 * that value.
4861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4863 This->stateBlock->state.base_vertex_index = 0;
4864 This->up_strided = DrawPrimStrideData;
4865 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4866 This->up_strided = NULL;
4867 return WINED3D_OK;
4870 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4871 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4872 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4875 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4877 /* Mark the state dirty until we have nicer tracking
4878 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4879 * that value.
4881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4883 This->stateBlock->state.user_stream = TRUE;
4884 This->stateBlock->state.base_vertex_index = 0;
4885 This->up_strided = DrawPrimStrideData;
4886 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4887 This->up_strided = NULL;
4888 return WINED3D_OK;
4891 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4892 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4893 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4895 WINED3DLOCKED_BOX src;
4896 WINED3DLOCKED_BOX dst;
4897 HRESULT hr;
4899 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4900 iface, pSourceVolume, pDestinationVolume);
4902 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4903 * dirtification to improve loading performance.
4905 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4906 if(FAILED(hr)) return hr;
4907 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4908 if(FAILED(hr)) {
4909 IWineD3DVolume_UnlockBox(pSourceVolume);
4910 return hr;
4913 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4915 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4916 if(FAILED(hr)) {
4917 IWineD3DVolume_UnlockBox(pSourceVolume);
4918 } else {
4919 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4921 return hr;
4924 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4925 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4927 unsigned int level_count, i;
4928 WINED3DRESOURCETYPE type;
4929 HRESULT hr;
4931 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4933 /* Verify that the source and destination textures are non-NULL. */
4934 if (!src_texture || !dst_texture)
4936 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4937 return WINED3DERR_INVALIDCALL;
4940 if (src_texture == dst_texture)
4942 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4943 return WINED3DERR_INVALIDCALL;
4946 /* Verify that the source and destination textures are the same type. */
4947 type = IWineD3DBaseTexture_GetType(src_texture);
4948 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4950 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4951 return WINED3DERR_INVALIDCALL;
4954 /* Check that both textures have the identical numbers of levels. */
4955 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4956 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4958 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4959 return WINED3DERR_INVALIDCALL;
4962 /* Make sure that the destination texture is loaded. */
4963 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4965 /* Update every surface level of the texture. */
4966 switch (type)
4968 case WINED3DRTYPE_TEXTURE:
4970 IWineD3DSurface *src_surface;
4971 IWineD3DSurface *dst_surface;
4973 for (i = 0; i < level_count; ++i)
4975 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4976 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4977 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4978 IWineD3DSurface_Release(dst_surface);
4979 IWineD3DSurface_Release(src_surface);
4980 if (FAILED(hr))
4982 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4983 return hr;
4986 break;
4989 case WINED3DRTYPE_CUBETEXTURE:
4991 IWineD3DSurface *src_surface;
4992 IWineD3DSurface *dst_surface;
4993 WINED3DCUBEMAP_FACES face;
4995 for (i = 0; i < level_count; ++i)
4997 /* Update each cube face. */
4998 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5000 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5001 face, i, &src_surface);
5002 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5003 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5004 face, i, &dst_surface);
5005 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5006 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5007 IWineD3DSurface_Release(dst_surface);
5008 IWineD3DSurface_Release(src_surface);
5009 if (FAILED(hr))
5011 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5012 return hr;
5016 break;
5019 case WINED3DRTYPE_VOLUMETEXTURE:
5021 IWineD3DVolume *src_volume;
5022 IWineD3DVolume *dst_volume;
5024 for (i = 0; i < level_count; ++i)
5026 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5027 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5028 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5029 IWineD3DVolume_Release(dst_volume);
5030 IWineD3DVolume_Release(src_volume);
5031 if (FAILED(hr))
5033 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5034 return hr;
5037 break;
5040 default:
5041 FIXME("Unsupported texture type %#x.\n", type);
5042 return WINED3DERR_INVALIDCALL;
5045 return WINED3D_OK;
5048 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5049 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5051 IWineD3DSwapChain *swapchain;
5052 HRESULT hr;
5054 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5056 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5057 if (FAILED(hr)) return hr;
5059 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5060 IWineD3DSwapChain_Release(swapchain);
5062 return hr;
5065 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 IWineD3DBaseTextureImpl *texture;
5068 DWORD i;
5070 TRACE("(%p) : %p\n", This, pNumPasses);
5072 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5074 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5076 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5077 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5079 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5081 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5082 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5085 texture = This->stateBlock->state.textures[i];
5086 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5088 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5090 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5091 return E_FAIL;
5093 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5095 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5096 return E_FAIL;
5098 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5099 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5101 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5102 return E_FAIL;
5106 /* return a sensible default */
5107 *pNumPasses = 1;
5109 TRACE("returning D3D_OK\n");
5110 return WINED3D_OK;
5113 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5115 int i;
5117 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5119 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5120 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5121 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5123 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5128 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 int j;
5131 UINT NewSize;
5132 PALETTEENTRY **palettes;
5134 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5136 if (PaletteNumber >= MAX_PALETTES) {
5137 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5138 return WINED3DERR_INVALIDCALL;
5141 if (PaletteNumber >= This->NumberOfPalettes) {
5142 NewSize = This->NumberOfPalettes;
5143 do {
5144 NewSize *= 2;
5145 } while(PaletteNumber >= NewSize);
5146 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5147 if (!palettes) {
5148 ERR("Out of memory!\n");
5149 return E_OUTOFMEMORY;
5151 This->palettes = palettes;
5152 This->NumberOfPalettes = NewSize;
5155 if (!This->palettes[PaletteNumber]) {
5156 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5157 if (!This->palettes[PaletteNumber]) {
5158 ERR("Out of memory!\n");
5159 return E_OUTOFMEMORY;
5163 for (j = 0; j < 256; ++j) {
5164 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5165 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5166 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5167 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5169 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5170 TRACE("(%p) : returning\n", This);
5171 return WINED3D_OK;
5174 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5176 int j;
5177 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5178 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5179 /* What happens in such situation isn't documented; Native seems to silently abort
5180 on such conditions. Return Invalid Call. */
5181 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5182 return WINED3DERR_INVALIDCALL;
5184 for (j = 0; j < 256; ++j) {
5185 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5186 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5187 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5188 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5190 TRACE("(%p) : returning\n", This);
5191 return WINED3D_OK;
5194 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5197 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5198 (tested with reference rasterizer). Return Invalid Call. */
5199 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5200 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5201 return WINED3DERR_INVALIDCALL;
5203 /*TODO: stateblocks */
5204 if (This->currentPalette != PaletteNumber) {
5205 This->currentPalette = PaletteNumber;
5206 dirtify_p8_texture_samplers(This);
5208 TRACE("(%p) : returning\n", This);
5209 return WINED3D_OK;
5212 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5215 if (!PaletteNumber)
5217 WARN("(%p) : returning Invalid Call\n", This);
5218 return WINED3DERR_INVALIDCALL;
5220 /*TODO: stateblocks */
5221 *PaletteNumber = This->currentPalette;
5222 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5223 return WINED3D_OK;
5226 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5228 static BOOL warned;
5229 if (!warned)
5231 FIXME("(%p) : stub\n", This);
5232 warned = TRUE;
5235 This->softwareVertexProcessing = bSoftware;
5236 return WINED3D_OK;
5240 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 static BOOL warned;
5243 if (!warned)
5245 FIXME("(%p) : stub\n", This);
5246 warned = TRUE;
5248 return This->softwareVertexProcessing;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5252 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5254 IWineD3DSwapChain *swapchain;
5255 HRESULT hr;
5257 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5258 iface, swapchain_idx, raster_status);
5260 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5261 if (FAILED(hr))
5263 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5264 return hr;
5267 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5268 IWineD3DSwapChain_Release(swapchain);
5269 if (FAILED(hr))
5271 WARN("Failed to get raster status, hr %#x.\n", hr);
5272 return hr;
5275 return WINED3D_OK;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5280 static BOOL warned;
5281 if(nSegments != 0.0f) {
5282 if (!warned)
5284 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5285 warned = TRUE;
5288 return WINED3D_OK;
5291 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5293 static BOOL warned;
5294 if (!warned)
5296 FIXME("iface %p stub!\n", iface);
5297 warned = TRUE;
5299 return 0.0f;
5302 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5303 IWineD3DSurface *src_surface, const RECT *src_rect,
5304 IWineD3DSurface *dst_surface, const POINT *dst_point)
5306 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5307 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 const struct wined3d_format *src_format;
5310 const struct wined3d_format *dst_format;
5311 const struct wined3d_gl_info *gl_info;
5312 struct wined3d_context *context;
5313 const unsigned char *data;
5314 UINT update_w, update_h;
5315 CONVERT_TYPES convert;
5316 UINT src_w, src_h;
5317 UINT dst_x, dst_y;
5318 DWORD sampler;
5319 struct wined3d_format format;
5321 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5322 iface, src_surface, wine_dbgstr_rect(src_rect),
5323 dst_surface, wine_dbgstr_point(dst_point));
5325 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5327 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5328 src_surface, dst_surface);
5329 return WINED3DERR_INVALIDCALL;
5332 src_format = src_impl->resource.format;
5333 dst_format = dst_impl->resource.format;
5335 if (src_format->id != dst_format->id)
5337 WARN("Source and destination surfaces should have the same format.\n");
5338 return WINED3DERR_INVALIDCALL;
5341 dst_x = dst_point ? dst_point->x : 0;
5342 dst_y = dst_point ? dst_point->y : 0;
5344 /* This call loads the OpenGL surface directly, instead of copying the
5345 * surface to the destination's sysmem copy. If surface conversion is
5346 * needed, use BltFast instead to copy in sysmem and use regular surface
5347 * loading. */
5348 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5349 if (convert != NO_CONVERSION || format.convert)
5350 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5352 context = context_acquire(This, NULL);
5353 gl_info = context->gl_info;
5355 ENTER_GL();
5356 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5357 checkGLcall("glActiveTextureARB");
5358 LEAVE_GL();
5360 /* Make sure the surface is loaded and up to date */
5361 surface_internal_preload(dst_impl, SRGB_RGB);
5362 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5364 src_w = src_impl->currentDesc.Width;
5365 src_h = src_impl->currentDesc.Height;
5366 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5367 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5369 data = IWineD3DSurface_GetData(src_surface);
5370 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5372 ENTER_GL();
5374 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5376 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5377 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5378 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5380 if (src_rect)
5382 data += (src_rect->top / src_format->block_height) * src_pitch;
5383 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5386 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5387 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5388 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5390 if (row_length == src_pitch)
5392 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5393 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5395 else
5397 UINT row, y;
5399 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5400 * can't use the unpack row length like below. */
5401 for (row = 0, y = dst_y; row < row_count; ++row)
5403 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5404 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5405 y += src_format->block_height;
5406 data += src_pitch;
5409 checkGLcall("glCompressedTexSubImage2DARB");
5411 else
5413 if (src_rect)
5415 data += src_rect->top * src_w * src_format->byte_count;
5416 data += src_rect->left * src_format->byte_count;
5419 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5420 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5421 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5423 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5424 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5425 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5426 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5427 checkGLcall("glTexSubImage2D");
5430 LEAVE_GL();
5431 context_release(context);
5433 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5434 sampler = This->rev_tex_unit_map[0];
5435 if (sampler != WINED3D_UNMAPPED_STAGE)
5437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5440 return WINED3D_OK;
5443 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5445 struct WineD3DRectPatch *patch;
5446 GLenum old_primitive_type;
5447 unsigned int i;
5448 struct list *e;
5449 BOOL found;
5450 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5452 if(!(Handle || pRectPatchInfo)) {
5453 /* TODO: Write a test for the return value, thus the FIXME */
5454 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5455 return WINED3DERR_INVALIDCALL;
5458 if(Handle) {
5459 i = PATCHMAP_HASHFUNC(Handle);
5460 found = FALSE;
5461 LIST_FOR_EACH(e, &This->patches[i]) {
5462 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5463 if(patch->Handle == Handle) {
5464 found = TRUE;
5465 break;
5469 if(!found) {
5470 TRACE("Patch does not exist. Creating a new one\n");
5471 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5472 patch->Handle = Handle;
5473 list_add_head(&This->patches[i], &patch->entry);
5474 } else {
5475 TRACE("Found existing patch %p\n", patch);
5477 } else {
5478 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5479 * attributes we have to tesselate, read back, and draw. This needs a patch
5480 * management structure instance. Create one.
5482 * A possible improvement is to check if a vertex shader is used, and if not directly
5483 * draw the patch.
5485 FIXME("Drawing an uncached patch. This is slow\n");
5486 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5489 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5490 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5491 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5493 HRESULT hr;
5494 TRACE("Tesselation density or patch info changed, retesselating\n");
5496 if(pRectPatchInfo) {
5497 patch->RectPatchInfo = *pRectPatchInfo;
5499 patch->numSegs[0] = pNumSegs[0];
5500 patch->numSegs[1] = pNumSegs[1];
5501 patch->numSegs[2] = pNumSegs[2];
5502 patch->numSegs[3] = pNumSegs[3];
5504 hr = tesselate_rectpatch(This, patch);
5505 if(FAILED(hr)) {
5506 WARN("Patch tesselation failed\n");
5508 /* Do not release the handle to store the params of the patch */
5509 if(!Handle) {
5510 HeapFree(GetProcessHeap(), 0, patch);
5512 return hr;
5516 This->currentPatch = patch;
5517 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5518 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5519 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5520 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5521 This->currentPatch = NULL;
5523 /* Destroy uncached patches */
5524 if(!Handle) {
5525 HeapFree(GetProcessHeap(), 0, patch->mem);
5526 HeapFree(GetProcessHeap(), 0, patch);
5528 return WINED3D_OK;
5531 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5532 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5534 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5535 iface, handle, segment_count, patch_info);
5537 return WINED3D_OK;
5540 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 int i;
5543 struct WineD3DRectPatch *patch;
5544 struct list *e;
5545 TRACE("(%p) Handle(%d)\n", This, Handle);
5547 i = PATCHMAP_HASHFUNC(Handle);
5548 LIST_FOR_EACH(e, &This->patches[i]) {
5549 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5550 if(patch->Handle == Handle) {
5551 TRACE("Deleting patch %p\n", patch);
5552 list_remove(&patch->entry);
5553 HeapFree(GetProcessHeap(), 0, patch->mem);
5554 HeapFree(GetProcessHeap(), 0, patch);
5555 return WINED3D_OK;
5559 /* TODO: Write a test for the return value */
5560 FIXME("Attempt to destroy nonexistent patch\n");
5561 return WINED3DERR_INVALIDCALL;
5564 /* Do not call while under the GL lock. */
5565 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5566 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5568 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5570 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5571 iface, surface, wine_dbgstr_rect(rect),
5572 color->r, color->g, color->b, color->a);
5574 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5576 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5577 return WINED3DERR_INVALIDCALL;
5580 return surface_color_fill(s, rect, color);
5583 /* Do not call while under the GL lock. */
5584 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5585 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5587 IWineD3DResource *resource;
5588 HRESULT hr;
5590 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5591 if (FAILED(hr))
5593 ERR("Failed to get resource, hr %#x\n", hr);
5594 return;
5597 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5599 FIXME("Only supported on surface resources\n");
5600 IWineD3DResource_Release(resource);
5601 return;
5604 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5605 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5607 IWineD3DResource_Release(resource);
5610 /* rendertarget and depth stencil functions */
5611 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5612 DWORD render_target_idx, IWineD3DSurface **render_target)
5614 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5616 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5617 iface, render_target_idx, render_target);
5619 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5621 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5622 return WINED3DERR_INVALIDCALL;
5625 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5626 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5628 TRACE("Returning render target %p.\n", *render_target);
5630 return WINED3D_OK;
5633 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5634 IWineD3DSurface *front, IWineD3DSurface *back)
5636 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5637 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5638 IWineD3DSwapChainImpl *swapchain;
5639 HRESULT hr;
5641 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5643 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5645 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5646 return hr;
5649 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5651 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5652 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5653 return WINED3DERR_INVALIDCALL;
5656 if (back_impl)
5658 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5660 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5661 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5662 return WINED3DERR_INVALIDCALL;
5665 if (!swapchain->back_buffers)
5667 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5668 if (!swapchain->back_buffers)
5670 ERR("Failed to allocate back buffer array memory.\n");
5671 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5672 return E_OUTOFMEMORY;
5677 if (swapchain->front_buffer != front_impl)
5679 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5681 if (swapchain->front_buffer)
5682 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5683 swapchain->front_buffer = front_impl;
5685 if (front_impl)
5686 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5689 if (swapchain->back_buffers[0] != back_impl)
5691 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5693 if (swapchain->back_buffers[0])
5694 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5695 swapchain->back_buffers[0] = back_impl;
5697 if (back_impl)
5699 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5700 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5701 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5702 swapchain->presentParms.BackBufferCount = 1;
5704 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5706 else
5708 swapchain->presentParms.BackBufferCount = 0;
5709 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5710 swapchain->back_buffers = NULL;
5714 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5715 return WINED3D_OK;
5718 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5720 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5722 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5724 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5725 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5726 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5727 IWineD3DSurface_AddRef(*depth_stencil);
5729 return WINED3D_OK;
5732 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5733 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5735 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5736 IWineD3DSurfaceImpl *prev;
5738 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5739 iface, render_target_idx, render_target, set_viewport);
5741 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5743 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5744 return WINED3DERR_INVALIDCALL;
5747 prev = device->render_targets[render_target_idx];
5748 if (render_target == (IWineD3DSurface *)prev)
5750 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5751 return WINED3D_OK;
5754 /* Render target 0 can't be set to NULL. */
5755 if (!render_target && !render_target_idx)
5757 WARN("Trying to set render target 0 to NULL.\n");
5758 return WINED3DERR_INVALIDCALL;
5761 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5763 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5764 return WINED3DERR_INVALIDCALL;
5767 if (render_target) IWineD3DSurface_AddRef(render_target);
5768 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5769 /* Release after the assignment, to prevent device_resource_released()
5770 * from seeing the surface as still in use. */
5771 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5773 /* Render target 0 is special. */
5774 if (!render_target_idx && set_viewport)
5776 /* Set the viewport and scissor rectangles, if requested. Tests show
5777 * that stateblock recording is ignored, the change goes directly
5778 * into the primary stateblock. */
5779 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5780 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5781 device->stateBlock->state.viewport.X = 0;
5782 device->stateBlock->state.viewport.Y = 0;
5783 device->stateBlock->state.viewport.MaxZ = 1.0f;
5784 device->stateBlock->state.viewport.MinZ = 0.0f;
5785 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5787 device->stateBlock->state.scissor_rect.top = 0;
5788 device->stateBlock->state.scissor_rect.left = 0;
5789 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5790 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5791 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5794 return WINED3D_OK;
5797 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 IWineD3DSurfaceImpl *tmp;
5802 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5804 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5806 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5807 return WINED3D_OK;
5810 if (This->depth_stencil)
5812 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5813 || This->depth_stencil->Flags & SFLAG_DISCARD)
5815 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5816 This->depth_stencil->currentDesc.Width,
5817 This->depth_stencil->currentDesc.Height);
5818 if (This->depth_stencil == This->onscreen_depth_stencil)
5820 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5821 This->onscreen_depth_stencil = NULL;
5826 tmp = This->depth_stencil;
5827 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5828 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5829 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5831 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5833 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5839 return WINED3D_OK;
5842 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5843 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5846 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5847 WINED3DLOCKED_RECT lockedRect;
5849 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5850 iface, XHotSpot, YHotSpot, cursor_image);
5852 /* some basic validation checks */
5853 if (This->cursorTexture)
5855 struct wined3d_context *context = context_acquire(This, NULL);
5856 ENTER_GL();
5857 glDeleteTextures(1, &This->cursorTexture);
5858 LEAVE_GL();
5859 context_release(context);
5860 This->cursorTexture = 0;
5863 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5864 This->haveHardwareCursor = TRUE;
5865 else
5866 This->haveHardwareCursor = FALSE;
5868 if (cursor_image)
5870 WINED3DLOCKED_RECT rect;
5872 /* MSDN: Cursor must be A8R8G8B8 */
5873 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5875 WARN("surface %p has an invalid format.\n", cursor_image);
5876 return WINED3DERR_INVALIDCALL;
5879 /* MSDN: Cursor must be smaller than the display mode */
5880 if (s->currentDesc.Width > This->ddraw_width
5881 || s->currentDesc.Height > This->ddraw_height)
5883 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5884 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5885 return WINED3DERR_INVALIDCALL;
5888 if (!This->haveHardwareCursor) {
5889 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5891 /* Do not store the surface's pointer because the application may
5892 * release it after setting the cursor image. Windows doesn't
5893 * addref the set surface, so we can't do this either without
5894 * creating circular refcount dependencies. Copy out the gl texture
5895 * instead.
5897 This->cursorWidth = s->currentDesc.Width;
5898 This->cursorHeight = s->currentDesc.Height;
5899 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5901 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5902 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5903 struct wined3d_context *context;
5904 char *mem, *bits = rect.pBits;
5905 GLint intfmt = format->glInternal;
5906 GLint gl_format = format->glFormat;
5907 GLint type = format->glType;
5908 INT height = This->cursorHeight;
5909 INT width = This->cursorWidth;
5910 INT bpp = format->byte_count;
5911 DWORD sampler;
5912 INT i;
5914 /* Reformat the texture memory (pitch and width can be
5915 * different) */
5916 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5917 for(i = 0; i < height; i++)
5918 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5919 IWineD3DSurface_UnlockRect(cursor_image);
5921 context = context_acquire(This, NULL);
5923 ENTER_GL();
5925 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5927 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5928 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5931 /* Make sure that a proper texture unit is selected */
5932 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5933 checkGLcall("glActiveTextureARB");
5934 sampler = This->rev_tex_unit_map[0];
5935 if (sampler != WINED3D_UNMAPPED_STAGE)
5937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5939 /* Create a new cursor texture */
5940 glGenTextures(1, &This->cursorTexture);
5941 checkGLcall("glGenTextures");
5942 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5943 checkGLcall("glBindTexture");
5944 /* Copy the bitmap memory into the cursor texture */
5945 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5946 HeapFree(GetProcessHeap(), 0, mem);
5947 checkGLcall("glTexImage2D");
5949 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5951 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5952 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5955 LEAVE_GL();
5957 context_release(context);
5959 else
5961 FIXME("A cursor texture was not returned.\n");
5962 This->cursorTexture = 0;
5965 else
5967 /* Draw a hardware cursor */
5968 ICONINFO cursorInfo;
5969 HCURSOR cursor;
5970 /* Create and clear maskBits because it is not needed for
5971 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5972 * chunks. */
5973 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5974 (s->currentDesc.Width * s->currentDesc.Height / 8));
5975 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5976 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5977 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5979 cursorInfo.fIcon = FALSE;
5980 cursorInfo.xHotspot = XHotSpot;
5981 cursorInfo.yHotspot = YHotSpot;
5982 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5983 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5984 IWineD3DSurface_UnlockRect(cursor_image);
5985 /* Create our cursor and clean up. */
5986 cursor = CreateIconIndirect(&cursorInfo);
5987 SetCursor(cursor);
5988 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5989 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5990 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5991 This->hardwareCursor = cursor;
5992 HeapFree(GetProcessHeap(), 0, maskBits);
5996 This->xHotSpot = XHotSpot;
5997 This->yHotSpot = YHotSpot;
5998 return WINED3D_OK;
6001 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6003 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6005 This->xScreenSpace = XScreenSpace;
6006 This->yScreenSpace = YScreenSpace;
6008 return;
6012 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6014 BOOL oldVisible = This->bCursorVisible;
6015 POINT pt;
6017 TRACE("(%p) : visible(%d)\n", This, bShow);
6020 * When ShowCursor is first called it should make the cursor appear at the OS's last
6021 * known cursor position. Because of this, some applications just repetitively call
6022 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6024 GetCursorPos(&pt);
6025 This->xScreenSpace = pt.x;
6026 This->yScreenSpace = pt.y;
6028 if (This->haveHardwareCursor) {
6029 This->bCursorVisible = bShow;
6030 if (bShow)
6031 SetCursor(This->hardwareCursor);
6032 else
6033 SetCursor(NULL);
6035 else
6037 if (This->cursorTexture)
6038 This->bCursorVisible = bShow;
6041 return oldVisible;
6044 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6045 TRACE("checking resource %p for eviction\n", resource);
6046 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6047 TRACE("Evicting %p\n", resource);
6048 IWineD3DResource_UnLoad(resource);
6050 IWineD3DResource_Release(resource);
6051 return S_OK;
6054 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6056 TRACE("iface %p.\n", iface);
6058 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6059 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6060 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6062 return WINED3D_OK;
6065 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6067 IWineD3DDeviceImpl *device = surface->resource.device;
6068 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6070 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6071 if(surface->Flags & SFLAG_DIBSECTION) {
6072 /* Release the DC */
6073 SelectObject(surface->hDC, surface->dib.holdbitmap);
6074 DeleteDC(surface->hDC);
6075 /* Release the DIB section */
6076 DeleteObject(surface->dib.DIBsection);
6077 surface->dib.bitmap_data = NULL;
6078 surface->resource.allocatedMemory = NULL;
6079 surface->Flags &= ~SFLAG_DIBSECTION;
6081 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6082 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6083 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6084 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6086 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6087 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6088 } else {
6089 surface->pow2Width = surface->pow2Height = 1;
6090 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6091 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6094 if (surface->texture_name)
6096 struct wined3d_context *context = context_acquire(device, NULL);
6097 ENTER_GL();
6098 glDeleteTextures(1, &surface->texture_name);
6099 LEAVE_GL();
6100 context_release(context);
6101 surface->texture_name = 0;
6102 surface->Flags &= ~SFLAG_CLIENT;
6104 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6105 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6106 surface->Flags |= SFLAG_NONPOW2;
6107 } else {
6108 surface->Flags &= ~SFLAG_NONPOW2;
6110 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6111 surface->resource.allocatedMemory = NULL;
6112 surface->resource.heapMemory = NULL;
6113 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6115 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6116 * to a FBO */
6117 if (!surface_init_sysmem(surface))
6119 return E_OUTOFMEMORY;
6121 return WINED3D_OK;
6124 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6125 TRACE("Unloading resource %p\n", resource);
6126 IWineD3DResource_UnLoad(resource);
6127 IWineD3DResource_Release(resource);
6128 return S_OK;
6131 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6133 UINT i, count;
6134 WINED3DDISPLAYMODE m;
6135 HRESULT hr;
6137 /* All Windowed modes are supported, as is leaving the current mode */
6138 if(pp->Windowed) return TRUE;
6139 if(!pp->BackBufferWidth) return TRUE;
6140 if(!pp->BackBufferHeight) return TRUE;
6142 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6143 for(i = 0; i < count; i++) {
6144 memset(&m, 0, sizeof(m));
6145 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6146 if(FAILED(hr)) {
6147 ERR("EnumAdapterModes failed\n");
6149 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6150 /* Mode found, it is supported */
6151 return TRUE;
6154 /* Mode not found -> not supported */
6155 return FALSE;
6158 /* Do not call while under the GL lock. */
6159 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6162 const struct wined3d_gl_info *gl_info;
6163 struct wined3d_context *context;
6164 IWineD3DBaseShaderImpl *shader;
6166 context = context_acquire(This, NULL);
6167 gl_info = context->gl_info;
6169 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6170 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6171 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6174 ENTER_GL();
6175 if(This->depth_blt_texture) {
6176 glDeleteTextures(1, &This->depth_blt_texture);
6177 This->depth_blt_texture = 0;
6179 if (This->depth_blt_rb) {
6180 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6181 This->depth_blt_rb = 0;
6182 This->depth_blt_rb_w = 0;
6183 This->depth_blt_rb_h = 0;
6185 LEAVE_GL();
6187 This->blitter->free_private(iface);
6188 This->frag_pipe->free_private(iface);
6189 This->shader_backend->shader_free_private(iface);
6190 destroy_dummy_textures(This, gl_info);
6192 context_release(context);
6194 while (This->numContexts)
6196 context_destroy(This, This->contexts[0]);
6198 HeapFree(GetProcessHeap(), 0, swapchain->context);
6199 swapchain->context = NULL;
6200 swapchain->num_contexts = 0;
6203 /* Do not call while under the GL lock. */
6204 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6207 struct wined3d_context *context;
6208 HRESULT hr;
6209 IWineD3DSurfaceImpl *target;
6211 /* Recreate the primary swapchain's context */
6212 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6213 if (!swapchain->context)
6215 ERR("Failed to allocate memory for swapchain context array.\n");
6216 return E_OUTOFMEMORY;
6219 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6220 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6222 WARN("Failed to create context.\n");
6223 HeapFree(GetProcessHeap(), 0, swapchain->context);
6224 return E_FAIL;
6227 swapchain->context[0] = context;
6228 swapchain->num_contexts = 1;
6229 create_dummy_textures(This);
6230 context_release(context);
6232 hr = This->shader_backend->shader_alloc_private(iface);
6233 if (FAILED(hr))
6235 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6236 goto err;
6239 hr = This->frag_pipe->alloc_private(iface);
6240 if (FAILED(hr))
6242 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6243 This->shader_backend->shader_free_private(iface);
6244 goto err;
6247 hr = This->blitter->alloc_private(iface);
6248 if (FAILED(hr))
6250 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6251 This->frag_pipe->free_private(iface);
6252 This->shader_backend->shader_free_private(iface);
6253 goto err;
6256 return WINED3D_OK;
6258 err:
6259 context_acquire(This, NULL);
6260 destroy_dummy_textures(This, context->gl_info);
6261 context_release(context);
6262 context_destroy(This, context);
6263 HeapFree(GetProcessHeap(), 0, swapchain->context);
6264 swapchain->num_contexts = 0;
6265 return hr;
6268 /* Do not call while under the GL lock. */
6269 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6270 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6273 IWineD3DSwapChainImpl *swapchain;
6274 HRESULT hr;
6275 BOOL DisplayModeChanged = FALSE;
6276 WINED3DDISPLAYMODE mode;
6277 TRACE("(%p)\n", This);
6279 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6280 if(FAILED(hr)) {
6281 ERR("Failed to get the first implicit swapchain\n");
6282 return hr;
6285 if(!is_display_mode_supported(This, pPresentationParameters)) {
6286 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6287 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6288 pPresentationParameters->BackBufferHeight);
6289 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6290 return WINED3DERR_INVALIDCALL;
6293 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6294 * on an existing gl context, so there's no real need for recreation.
6296 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6298 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6300 TRACE("New params:\n");
6301 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6302 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6303 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6304 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6305 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6306 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6307 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6308 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6309 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6310 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6311 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6312 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6313 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6315 /* No special treatment of these parameters. Just store them */
6316 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6317 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6318 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6319 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6321 /* What to do about these? */
6322 if (pPresentationParameters->BackBufferCount
6323 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6324 ERR("Cannot change the back buffer count yet\n");
6326 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6327 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6328 ERR("Cannot change the back buffer format yet\n");
6331 if (pPresentationParameters->hDeviceWindow
6332 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6333 ERR("Cannot change the device window yet\n");
6335 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6337 HRESULT hrc;
6339 TRACE("Creating the depth stencil buffer\n");
6341 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6342 pPresentationParameters->BackBufferWidth,
6343 pPresentationParameters->BackBufferHeight,
6344 pPresentationParameters->AutoDepthStencilFormat,
6345 pPresentationParameters->MultiSampleType,
6346 pPresentationParameters->MultiSampleQuality,
6347 FALSE,
6348 (IWineD3DSurface **)&This->auto_depth_stencil);
6350 if (FAILED(hrc)) {
6351 ERR("Failed to create the depth stencil buffer\n");
6352 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6353 return WINED3DERR_INVALIDCALL;
6357 if (This->onscreen_depth_stencil)
6359 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6360 This->onscreen_depth_stencil = NULL;
6363 /* Reset the depth stencil */
6364 if (pPresentationParameters->EnableAutoDepthStencil)
6365 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6366 else
6367 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6369 TRACE("Resetting stateblock\n");
6370 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6371 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6373 delete_opengl_contexts(iface, swapchain);
6375 if(pPresentationParameters->Windowed) {
6376 mode.Width = swapchain->orig_width;
6377 mode.Height = swapchain->orig_height;
6378 mode.RefreshRate = 0;
6379 mode.Format = swapchain->presentParms.BackBufferFormat;
6380 } else {
6381 mode.Width = pPresentationParameters->BackBufferWidth;
6382 mode.Height = pPresentationParameters->BackBufferHeight;
6383 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6384 mode.Format = swapchain->presentParms.BackBufferFormat;
6387 /* Should Width == 800 && Height == 0 set 800x600? */
6388 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6389 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6390 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6392 UINT i;
6394 if(!pPresentationParameters->Windowed) {
6395 DisplayModeChanged = TRUE;
6397 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6398 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6400 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6401 if(FAILED(hr))
6403 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6404 return hr;
6407 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6409 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6410 if(FAILED(hr))
6412 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6413 return hr;
6416 if (This->auto_depth_stencil)
6418 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6419 if(FAILED(hr))
6421 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6422 return hr;
6427 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6428 || DisplayModeChanged)
6430 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6432 if (!pPresentationParameters->Windowed)
6434 if(swapchain->presentParms.Windowed) {
6435 /* switch from windowed to fs */
6436 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6437 pPresentationParameters->BackBufferHeight);
6438 } else {
6439 /* Fullscreen -> fullscreen mode change */
6440 MoveWindow(swapchain->device_window, 0, 0,
6441 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6442 TRUE);
6445 else if (!swapchain->presentParms.Windowed)
6447 /* Fullscreen -> windowed switch */
6448 swapchain_restore_fullscreen_window(swapchain);
6450 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6451 } else if(!pPresentationParameters->Windowed) {
6452 DWORD style = This->style, exStyle = This->exStyle;
6453 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6454 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6455 * Reset to clear up their mess. Guild Wars also loses the device during that.
6457 This->style = 0;
6458 This->exStyle = 0;
6459 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6460 pPresentationParameters->BackBufferHeight);
6461 This->style = style;
6462 This->exStyle = exStyle;
6465 /* Note: No parent needed for initial internal stateblock */
6466 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6467 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6468 else TRACE("Created stateblock %p\n", This->stateBlock);
6469 This->updateStateBlock = This->stateBlock;
6470 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6472 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6473 if(FAILED(hr)) {
6474 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6477 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6479 RECT client_rect;
6480 GetClientRect(swapchain->win_handle, &client_rect);
6482 if(!swapchain->presentParms.BackBufferCount)
6484 TRACE("Single buffered rendering\n");
6485 swapchain->render_to_fbo = FALSE;
6487 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6488 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6490 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6491 swapchain->presentParms.BackBufferWidth,
6492 swapchain->presentParms.BackBufferHeight,
6493 client_rect.right, client_rect.bottom);
6494 swapchain->render_to_fbo = TRUE;
6496 else
6498 TRACE("Rendering directly to GL_BACK\n");
6499 swapchain->render_to_fbo = FALSE;
6503 hr = create_primary_opengl_context(iface, swapchain);
6504 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6506 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6507 * first use
6509 return hr;
6512 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6514 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6516 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6518 return WINED3D_OK;
6522 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6524 TRACE("(%p) : pParameters %p\n", This, pParameters);
6526 *pParameters = This->createParms;
6527 return WINED3D_OK;
6530 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6531 IWineD3DSwapChain *swapchain;
6533 TRACE("Relaying to swapchain\n");
6535 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6536 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6537 IWineD3DSwapChain_Release(swapchain);
6541 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6542 IWineD3DSwapChain *swapchain;
6544 TRACE("Relaying to swapchain\n");
6546 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6547 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6548 IWineD3DSwapChain_Release(swapchain);
6553 /** ********************************************************
6554 * Notification functions
6555 ** ********************************************************/
6556 /** This function must be called in the release of a resource when ref == 0,
6557 * the contents of resource must still be correct,
6558 * any handles to other resource held by the caller must be closed
6559 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6560 *****************************************************/
6561 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6563 TRACE("(%p) : Adding resource %p\n", This, resource);
6565 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6568 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6570 TRACE("(%p) : Removing resource %p\n", This, resource);
6572 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6575 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6577 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6578 unsigned int i;
6580 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6582 context_resource_released(device, resource, type);
6584 switch (type)
6586 case WINED3DRTYPE_SURFACE:
6587 if (!device->d3d_initialized) break;
6589 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6591 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6593 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6594 device->render_targets[i] = NULL;
6598 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6600 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6601 device->depth_stencil = NULL;
6603 break;
6605 case WINED3DRTYPE_TEXTURE:
6606 case WINED3DRTYPE_CUBETEXTURE:
6607 case WINED3DRTYPE_VOLUMETEXTURE:
6608 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6610 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6612 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6613 resource, device->stateBlock, i);
6614 device->stateBlock->state.textures[i] = NULL;
6617 if (device->updateStateBlock != device->stateBlock
6618 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6620 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6621 resource, device->updateStateBlock, i);
6622 device->updateStateBlock->state.textures[i] = NULL;
6625 break;
6627 case WINED3DRTYPE_BUFFER:
6628 for (i = 0; i < MAX_STREAMS; ++i)
6630 if (device->stateBlock
6631 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6633 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6634 resource, device->stateBlock, i);
6635 device->stateBlock->state.streams[i].buffer = NULL;
6638 if (device->updateStateBlock != device->stateBlock
6639 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6641 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6642 resource, device->updateStateBlock, i);
6643 device->updateStateBlock->state.streams[i].buffer = NULL;
6648 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6650 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6651 resource, device->stateBlock);
6652 device->stateBlock->state.index_buffer = NULL;
6655 if (device->updateStateBlock != device->stateBlock
6656 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6658 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6659 resource, device->updateStateBlock);
6660 device->updateStateBlock->state.index_buffer = NULL;
6662 break;
6664 default:
6665 break;
6668 /* Remove the resource from the resourceStore */
6669 device_resource_remove(device, resource);
6671 TRACE("Resource released.\n");
6674 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6676 IWineD3DResourceImpl *resource, *cursor;
6677 HRESULT ret;
6678 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6680 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6681 TRACE("enumerating resource %p\n", resource);
6682 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6683 ret = pCallback((IWineD3DResource *) resource, pData);
6684 if(ret == S_FALSE) {
6685 TRACE("Canceling enumeration\n");
6686 break;
6689 return WINED3D_OK;
6692 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6695 IWineD3DResourceImpl *resource;
6697 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6699 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6700 if (type == WINED3DRTYPE_SURFACE)
6702 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6704 TRACE("Found surface %p for dc %p.\n", resource, dc);
6705 *surface = (IWineD3DSurface *)resource;
6706 return WINED3D_OK;
6711 return WINED3DERR_INVALIDCALL;
6714 /**********************************************************
6715 * IWineD3DDevice VTbl follows
6716 **********************************************************/
6718 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6720 /*** IUnknown methods ***/
6721 IWineD3DDeviceImpl_QueryInterface,
6722 IWineD3DDeviceImpl_AddRef,
6723 IWineD3DDeviceImpl_Release,
6724 /*** IWineD3DDevice methods ***/
6725 /*** Creation methods**/
6726 IWineD3DDeviceImpl_CreateBuffer,
6727 IWineD3DDeviceImpl_CreateVertexBuffer,
6728 IWineD3DDeviceImpl_CreateIndexBuffer,
6729 IWineD3DDeviceImpl_CreateStateBlock,
6730 IWineD3DDeviceImpl_CreateSurface,
6731 IWineD3DDeviceImpl_CreateRendertargetView,
6732 IWineD3DDeviceImpl_CreateTexture,
6733 IWineD3DDeviceImpl_CreateVolumeTexture,
6734 IWineD3DDeviceImpl_CreateVolume,
6735 IWineD3DDeviceImpl_CreateCubeTexture,
6736 IWineD3DDeviceImpl_CreateQuery,
6737 IWineD3DDeviceImpl_CreateSwapChain,
6738 IWineD3DDeviceImpl_CreateVertexDeclaration,
6739 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6740 IWineD3DDeviceImpl_CreateVertexShader,
6741 IWineD3DDeviceImpl_CreateGeometryShader,
6742 IWineD3DDeviceImpl_CreatePixelShader,
6743 IWineD3DDeviceImpl_CreatePalette,
6744 /*** Odd functions **/
6745 IWineD3DDeviceImpl_Init3D,
6746 IWineD3DDeviceImpl_InitGDI,
6747 IWineD3DDeviceImpl_Uninit3D,
6748 IWineD3DDeviceImpl_UninitGDI,
6749 IWineD3DDeviceImpl_SetMultithreaded,
6750 IWineD3DDeviceImpl_EvictManagedResources,
6751 IWineD3DDeviceImpl_GetAvailableTextureMem,
6752 IWineD3DDeviceImpl_GetBackBuffer,
6753 IWineD3DDeviceImpl_GetCreationParameters,
6754 IWineD3DDeviceImpl_GetDeviceCaps,
6755 IWineD3DDeviceImpl_GetDirect3D,
6756 IWineD3DDeviceImpl_GetDisplayMode,
6757 IWineD3DDeviceImpl_SetDisplayMode,
6758 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6759 IWineD3DDeviceImpl_GetRasterStatus,
6760 IWineD3DDeviceImpl_GetSwapChain,
6761 IWineD3DDeviceImpl_Reset,
6762 IWineD3DDeviceImpl_SetDialogBoxMode,
6763 IWineD3DDeviceImpl_SetCursorProperties,
6764 IWineD3DDeviceImpl_SetCursorPosition,
6765 IWineD3DDeviceImpl_ShowCursor,
6766 /*** Getters and setters **/
6767 IWineD3DDeviceImpl_SetClipPlane,
6768 IWineD3DDeviceImpl_GetClipPlane,
6769 IWineD3DDeviceImpl_SetClipStatus,
6770 IWineD3DDeviceImpl_GetClipStatus,
6771 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6772 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6773 IWineD3DDeviceImpl_SetDepthStencilSurface,
6774 IWineD3DDeviceImpl_GetDepthStencilSurface,
6775 IWineD3DDeviceImpl_SetGammaRamp,
6776 IWineD3DDeviceImpl_GetGammaRamp,
6777 IWineD3DDeviceImpl_SetIndexBuffer,
6778 IWineD3DDeviceImpl_GetIndexBuffer,
6779 IWineD3DDeviceImpl_SetBaseVertexIndex,
6780 IWineD3DDeviceImpl_GetBaseVertexIndex,
6781 IWineD3DDeviceImpl_SetLight,
6782 IWineD3DDeviceImpl_GetLight,
6783 IWineD3DDeviceImpl_SetLightEnable,
6784 IWineD3DDeviceImpl_GetLightEnable,
6785 IWineD3DDeviceImpl_SetMaterial,
6786 IWineD3DDeviceImpl_GetMaterial,
6787 IWineD3DDeviceImpl_SetNPatchMode,
6788 IWineD3DDeviceImpl_GetNPatchMode,
6789 IWineD3DDeviceImpl_SetPaletteEntries,
6790 IWineD3DDeviceImpl_GetPaletteEntries,
6791 IWineD3DDeviceImpl_SetPixelShader,
6792 IWineD3DDeviceImpl_GetPixelShader,
6793 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6794 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6795 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6796 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6797 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6798 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6799 IWineD3DDeviceImpl_SetRenderState,
6800 IWineD3DDeviceImpl_GetRenderState,
6801 IWineD3DDeviceImpl_SetRenderTarget,
6802 IWineD3DDeviceImpl_GetRenderTarget,
6803 IWineD3DDeviceImpl_SetFrontBackBuffers,
6804 IWineD3DDeviceImpl_SetSamplerState,
6805 IWineD3DDeviceImpl_GetSamplerState,
6806 IWineD3DDeviceImpl_SetScissorRect,
6807 IWineD3DDeviceImpl_GetScissorRect,
6808 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6809 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6810 IWineD3DDeviceImpl_SetStreamSource,
6811 IWineD3DDeviceImpl_GetStreamSource,
6812 IWineD3DDeviceImpl_SetStreamSourceFreq,
6813 IWineD3DDeviceImpl_GetStreamSourceFreq,
6814 IWineD3DDeviceImpl_SetTexture,
6815 IWineD3DDeviceImpl_GetTexture,
6816 IWineD3DDeviceImpl_SetTextureStageState,
6817 IWineD3DDeviceImpl_GetTextureStageState,
6818 IWineD3DDeviceImpl_SetTransform,
6819 IWineD3DDeviceImpl_GetTransform,
6820 IWineD3DDeviceImpl_SetVertexDeclaration,
6821 IWineD3DDeviceImpl_GetVertexDeclaration,
6822 IWineD3DDeviceImpl_SetVertexShader,
6823 IWineD3DDeviceImpl_GetVertexShader,
6824 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6825 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6826 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6827 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6828 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6829 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6830 IWineD3DDeviceImpl_SetViewport,
6831 IWineD3DDeviceImpl_GetViewport,
6832 IWineD3DDeviceImpl_MultiplyTransform,
6833 IWineD3DDeviceImpl_ValidateDevice,
6834 IWineD3DDeviceImpl_ProcessVertices,
6835 /*** State block ***/
6836 IWineD3DDeviceImpl_BeginStateBlock,
6837 IWineD3DDeviceImpl_EndStateBlock,
6838 /*** Scene management ***/
6839 IWineD3DDeviceImpl_BeginScene,
6840 IWineD3DDeviceImpl_EndScene,
6841 IWineD3DDeviceImpl_Present,
6842 IWineD3DDeviceImpl_Clear,
6843 IWineD3DDeviceImpl_ClearRendertargetView,
6844 /*** Drawing ***/
6845 IWineD3DDeviceImpl_SetPrimitiveType,
6846 IWineD3DDeviceImpl_GetPrimitiveType,
6847 IWineD3DDeviceImpl_DrawPrimitive,
6848 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6849 IWineD3DDeviceImpl_DrawPrimitiveUP,
6850 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6851 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6852 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6853 IWineD3DDeviceImpl_DrawRectPatch,
6854 IWineD3DDeviceImpl_DrawTriPatch,
6855 IWineD3DDeviceImpl_DeletePatch,
6856 IWineD3DDeviceImpl_ColorFill,
6857 IWineD3DDeviceImpl_UpdateTexture,
6858 IWineD3DDeviceImpl_UpdateSurface,
6859 IWineD3DDeviceImpl_GetFrontBufferData,
6860 /*** object tracking ***/
6861 IWineD3DDeviceImpl_EnumResources,
6862 IWineD3DDeviceImpl_GetSurfaceFromDC,
6863 IWineD3DDeviceImpl_AcquireFocusWindow,
6864 IWineD3DDeviceImpl_ReleaseFocusWindow,
6867 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6868 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6869 IWineD3DDeviceParent *device_parent)
6871 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6872 const struct fragment_pipeline *fragment_pipeline;
6873 struct shader_caps shader_caps;
6874 struct fragment_caps ffp_caps;
6875 WINED3DDISPLAYMODE mode;
6876 unsigned int i;
6877 HRESULT hr;
6879 device->lpVtbl = &IWineD3DDevice_Vtbl;
6880 device->ref = 1;
6881 device->wined3d = (IWineD3D *)wined3d;
6882 IWineD3D_AddRef(device->wined3d);
6883 device->adapter = wined3d->adapter_count ? adapter : NULL;
6884 device->device_parent = device_parent;
6885 list_init(&device->resources);
6886 list_init(&device->shaders);
6888 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6889 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6891 /* Get the initial screen setup for ddraw. */
6892 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6893 if (FAILED(hr))
6895 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6896 IWineD3D_Release(device->wined3d);
6897 return hr;
6899 device->ddraw_width = mode.Width;
6900 device->ddraw_height = mode.Height;
6901 device->ddraw_format = mode.Format;
6903 /* Save the creation parameters. */
6904 device->createParms.AdapterOrdinal = adapter_idx;
6905 device->createParms.DeviceType = device_type;
6906 device->createParms.hFocusWindow = focus_window;
6907 device->createParms.BehaviorFlags = flags;
6909 device->devType = device_type;
6910 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6912 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6913 device->shader_backend = adapter->shader_backend;
6915 if (device->shader_backend)
6917 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6918 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6919 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6920 device->vs_clipping = shader_caps.VSClipping;
6922 fragment_pipeline = adapter->fragment_pipe;
6923 device->frag_pipe = fragment_pipeline;
6924 if (fragment_pipeline)
6926 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6927 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6929 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6930 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6931 if (FAILED(hr))
6933 ERR("Failed to compile state table, hr %#x.\n", hr);
6934 IWineD3D_Release(device->wined3d);
6935 return hr;
6938 device->blitter = adapter->blitter;
6940 return WINED3D_OK;
6944 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6945 DWORD rep = This->StateTable[state].representative;
6946 struct wined3d_context *context;
6947 DWORD idx;
6948 BYTE shift;
6949 UINT i;
6951 for(i = 0; i < This->numContexts; i++) {
6952 context = This->contexts[i];
6953 if(isStateDirty(context, rep)) continue;
6955 context->dirtyArray[context->numDirtyEntries++] = rep;
6956 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6957 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6958 context->isStateDirty[idx] |= (1 << shift);
6962 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6964 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6965 *width = context->current_rt->pow2Width;
6966 *height = context->current_rt->pow2Height;
6969 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6971 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6972 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6973 * current context's drawable, which is the size of the back buffer of the swapchain
6974 * the active context belongs to. */
6975 *width = swapchain->presentParms.BackBufferWidth;
6976 *height = swapchain->presentParms.BackBufferHeight;
6979 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6980 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6982 if (device->filter_messages)
6984 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6985 window, message, wparam, lparam);
6986 return DefWindowProcW(window, message, wparam, lparam);
6989 if (message == WM_DESTROY)
6991 TRACE("unregister window %p.\n", window);
6992 wined3d_unregister_window(window);
6994 if (device->focus_window == window) device->focus_window = NULL;
6995 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6998 return CallWindowProcW(proc, window, message, wparam, lparam);