wined3d: Recognize the SM4 NULL register type.
[wine/multimedia.git] / dlls / wined3d / device.c
blob97acd5f9946096e4e78bc3a4ba5c82857eb71171
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
181 unsigned int i;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
210 buffer_object = 0;
211 data = (BYTE *)buffer;
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((IWineD3DBuffer *)buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
227 buffer_object = 0;
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 warned = TRUE;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
278 stride_used = FALSE;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
333 if (buffer->query)
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
345 e->stream_idx = 0;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
352 unsigned int i;
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
412 BOOL fixup = FALSE;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
421 else
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
434 else
436 device->useDrawStridedSlow = FALSE;
439 else
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
449 else
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = state->textures[idx])) return;
462 srgb = state->sampler_states[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 const struct wined3d_state *state = &device->stateBlock->state;
469 unsigned int i;
471 if (use_vs(state))
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
480 if (use_ps(state))
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(state, i);
488 else
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
494 if (ffu_map & 1)
495 device_preload_texture(state, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
509 if (!new_array)
511 ERR("Failed to grow the context array.\n");
512 return FALSE;
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
517 return TRUE;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
523 BOOL found = FALSE;
524 UINT i;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
532 found = TRUE;
533 break;
537 if (!found)
539 ERR("Context %p doesn't exist in context array.\n", context);
540 return;
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
547 return;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
552 if (!new_array)
554 ERR("Failed to shrink context array. Oh well.\n");
555 return;
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
596 return FALSE;
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
602 return FALSE;
604 return TRUE;
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(&current_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
616 else
617 SetRectEmpty(&current_rect);
619 IntersectRect(&r, draw_rect, &current_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
624 return;
627 if (EqualRect(&r, &current_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
631 if (!clear_rect)
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
635 return;
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 return;
647 /* Full load. */
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
663 unsigned int i;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
682 if (!context->valid)
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
686 return WINED3D_OK;
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
693 ENTER_GL();
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
703 glStencilMask(~0U);
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
716 LEAVE_GL();
717 device_switch_onscreen_ds(device, context, depth_stencil);
718 ENTER_GL();
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
725 glClearDepth(depth);
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
747 if (!clear_rect)
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
754 else
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
760 glClear(clear_mask);
761 checkGLcall("glClear");
763 else
765 RECT current_rect;
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(&current_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
783 continue;
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
791 else
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
798 glClear(clear_mask);
799 checkGLcall("glClear");
803 LEAVE_GL();
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
811 return WINED3D_OK;
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
827 *object = iface;
828 return S_OK;
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
833 *object = NULL;
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
842 return refCount;
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
851 if (!refCount) {
852 UINT i;
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
884 This = NULL;
886 return refCount;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
894 HRESULT hr;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
909 if (FAILED(hr))
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 return hr;
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
921 return WINED3D_OK;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
930 HRESULT hr;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
946 if (!object)
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
955 if (FAILED(hr))
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
959 return hr;
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
974 HRESULT hr;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
980 if (!object)
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
989 parent, parent_ops);
990 if (FAILED(hr))
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
994 return hr;
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1001 return WINED3D_OK;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1009 HRESULT hr;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1012 if(!object)
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1019 if (FAILED(hr))
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1023 return hr;
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1039 HRESULT hr;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054 if (!object)
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1062 if (FAILED(hr))
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1066 return hr;
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1073 return hr;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1085 if (!object)
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1096 return WINED3D_OK;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1105 HRESULT hr;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1112 if (!object)
1114 ERR("Out of memory\n");
1115 *ppTexture = NULL;
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1120 if (FAILED(hr))
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1124 *ppTexture = NULL;
1125 return hr;
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1132 return WINED3D_OK;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1141 HRESULT hr;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1147 if (!object)
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1155 if (FAILED(hr))
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1160 return hr;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1166 return WINED3D_OK;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1175 HRESULT hr;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1181 if (!object)
1183 ERR("Out of memory\n");
1184 *ppVolume = NULL;
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1189 if (FAILED(hr))
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1193 return hr;
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1199 return WINED3D_OK;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1208 HRESULT hr;
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1211 if (!object)
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1219 if (FAILED(hr))
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1224 return hr;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1230 return WINED3D_OK;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1238 HRESULT hr;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1243 if (!object)
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1250 if (FAILED(hr))
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1254 return hr;
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1260 return WINED3D_OK;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1270 HRESULT hr;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1276 if (!object)
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1283 if (FAILED(hr))
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1287 return hr;
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1293 return WINED3D_OK;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1312 return WINED3D_OK;
1313 } else {
1314 TRACE("Swapchain out of range\n");
1315 *pSwapChain = NULL;
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1326 HRESULT hr;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1332 if(!object)
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1339 if (FAILED(hr))
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1343 return hr;
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1349 return WINED3D_OK;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1356 UINT offset;
1357 UINT idx;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1378 ++state->idx;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1399 unsigned int size;
1400 unsigned int idx;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1411 state.offset = 0;
1412 state.idx = 0;
1414 if (has_pos)
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1420 else
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1428 else
1430 switch (num_blends)
1432 case 1:
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 break;
1435 case 2:
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 break;
1438 case 3:
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 break;
1441 case 4:
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 default:
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1450 if (has_blend_idx)
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1457 else
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1472 break;
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1475 break;
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 break;
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1485 *ppVertexElements = state.elements;
1486 return size;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1495 unsigned int size;
1496 DWORD hr;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1505 return hr;
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1515 HRESULT hr;
1517 if (This->vs_selected_mode == SHADER_NONE)
1518 return WINED3DERR_INVALIDCALL;
1520 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1521 if (!object)
1523 ERR("Failed to allocate shader memory.\n");
1524 return E_OUTOFMEMORY;
1527 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1528 if (FAILED(hr))
1530 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1531 HeapFree(GetProcessHeap(), 0, object);
1532 return hr;
1535 TRACE("Created vertex shader %p.\n", object);
1536 *ppVertexShader = (IWineD3DVertexShader *)object;
1538 return WINED3D_OK;
1541 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1542 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1543 void *parent, const struct wined3d_parent_ops *parent_ops,
1544 IWineD3DGeometryShader **shader)
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 struct wined3d_geometryshader *object;
1548 HRESULT hr;
1550 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1551 if (!object)
1553 ERR("Failed to allocate shader memory.\n");
1554 return E_OUTOFMEMORY;
1557 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1558 if (FAILED(hr))
1560 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1561 HeapFree(GetProcessHeap(), 0, object);
1562 return hr;
1565 TRACE("Created geometry shader %p.\n", object);
1566 *shader = (IWineD3DGeometryShader *)object;
1568 return WINED3D_OK;
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1572 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1573 void *parent, const struct wined3d_parent_ops *parent_ops,
1574 IWineD3DPixelShader **ppPixelShader)
1576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1577 IWineD3DPixelShaderImpl *object;
1578 HRESULT hr;
1580 if (This->ps_selected_mode == SHADER_NONE)
1581 return WINED3DERR_INVALIDCALL;
1583 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1584 if (!object)
1586 ERR("Failed to allocate shader memory.\n");
1587 return E_OUTOFMEMORY;
1590 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1591 if (FAILED(hr))
1593 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1594 HeapFree(GetProcessHeap(), 0, object);
1595 return hr;
1598 TRACE("Created pixel shader %p.\n", object);
1599 *ppPixelShader = (IWineD3DPixelShader *)object;
1601 return WINED3D_OK;
1604 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1605 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1608 IWineD3DPaletteImpl *object;
1609 HRESULT hr;
1611 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1612 iface, Flags, PalEnt, Palette, parent);
1614 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1615 if (!object)
1617 ERR("Failed to allocate palette memory.\n");
1618 return E_OUTOFMEMORY;
1621 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1622 if (FAILED(hr))
1624 WARN("Failed to initialize palette, hr %#x.\n", hr);
1625 HeapFree(GetProcessHeap(), 0, object);
1626 return hr;
1629 TRACE("Created palette %p.\n", object);
1630 *Palette = (IWineD3DPalette *)object;
1632 return WINED3D_OK;
1635 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1636 HBITMAP hbm;
1637 BITMAP bm;
1638 HRESULT hr;
1639 HDC dcb = NULL, dcs = NULL;
1640 WINEDDCOLORKEY colorkey;
1642 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1643 if(hbm)
1645 GetObjectA(hbm, sizeof(BITMAP), &bm);
1646 dcb = CreateCompatibleDC(NULL);
1647 if(!dcb) goto out;
1648 SelectObject(dcb, hbm);
1650 else
1652 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1653 * couldn't be loaded
1655 memset(&bm, 0, sizeof(bm));
1656 bm.bmWidth = 32;
1657 bm.bmHeight = 32;
1660 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1661 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1662 &wined3d_null_parent_ops, &This->logo_surface);
1663 if (FAILED(hr))
1665 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1666 goto out;
1669 if(dcb) {
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1679 else
1681 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1686 out:
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1695 unsigned int i;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1701 ENTER_GL();
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1739 LEAVE_GL();
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1745 ENTER_GL();
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1748 LEAVE_GL();
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1755 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1757 if (!wined3d_register_window(window, device))
1759 ERR("Failed to register window %p.\n", window);
1760 return E_FAIL;
1763 device->focus_window = window;
1764 SetForegroundWindow(window);
1766 return WINED3D_OK;
1769 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1771 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1773 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1774 device->focus_window = NULL;
1777 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1778 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1781 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1782 IWineD3DSwapChainImpl *swapchain = NULL;
1783 struct wined3d_context *context;
1784 HRESULT hr;
1785 DWORD state;
1786 unsigned int i;
1788 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1790 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1791 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1793 TRACE("(%p) : Creating stateblock\n", This);
1794 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1795 if (FAILED(hr))
1797 WARN("Failed to create stateblock\n");
1798 goto err_out;
1800 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1801 This->updateStateBlock = This->stateBlock;
1802 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1804 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1805 sizeof(*This->render_targets) * gl_info->limits.buffers);
1807 This->NumberOfPalettes = 1;
1808 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1809 if (!This->palettes || !This->render_targets)
1811 ERR("Out of memory!\n");
1812 hr = E_OUTOFMEMORY;
1813 goto err_out;
1815 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1816 if(!This->palettes[0]) {
1817 ERR("Out of memory!\n");
1818 hr = E_OUTOFMEMORY;
1819 goto err_out;
1821 for (i = 0; i < 256; ++i) {
1822 This->palettes[0][i].peRed = 0xFF;
1823 This->palettes[0][i].peGreen = 0xFF;
1824 This->palettes[0][i].peBlue = 0xFF;
1825 This->palettes[0][i].peFlags = 0xFF;
1827 This->currentPalette = 0;
1829 /* Initialize the texture unit mapping to a 1:1 mapping */
1830 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1832 if (state < gl_info->limits.fragment_samplers)
1834 This->texUnitMap[state] = state;
1835 This->rev_tex_unit_map[state] = state;
1836 } else {
1837 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1838 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1842 /* Setup the implicit swapchain. This also initializes a context. */
1843 TRACE("Creating implicit swapchain\n");
1844 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1845 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1846 if (FAILED(hr))
1848 WARN("Failed to create implicit swapchain\n");
1849 goto err_out;
1852 This->NumberOfSwapChains = 1;
1853 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1854 if(!This->swapchains) {
1855 ERR("Out of memory!\n");
1856 goto err_out;
1858 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1860 if (swapchain->back_buffers && swapchain->back_buffers[0])
1862 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1863 This->render_targets[0] = swapchain->back_buffers[0];
1865 else
1867 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1868 This->render_targets[0] = swapchain->front_buffer;
1870 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1872 /* Depth Stencil support */
1873 This->depth_stencil = This->auto_depth_stencil;
1874 if (This->depth_stencil)
1875 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1877 hr = This->shader_backend->shader_alloc_private(iface);
1878 if(FAILED(hr)) {
1879 TRACE("Shader private data couldn't be allocated\n");
1880 goto err_out;
1882 hr = This->frag_pipe->alloc_private(iface);
1883 if(FAILED(hr)) {
1884 TRACE("Fragment pipeline private data couldn't be allocated\n");
1885 goto err_out;
1887 hr = This->blitter->alloc_private(iface);
1888 if(FAILED(hr)) {
1889 TRACE("Blitter private data couldn't be allocated\n");
1890 goto err_out;
1893 /* Set up some starting GL setup */
1895 /* Setup all the devices defaults */
1896 stateblock_init_default_state(This->stateBlock);
1898 context = context_acquire(This, swapchain->front_buffer);
1900 create_dummy_textures(This);
1902 ENTER_GL();
1904 /* Initialize the current view state */
1905 This->view_ident = 1;
1906 This->contexts[0]->last_was_rhw = 0;
1907 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1908 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1910 switch(wined3d_settings.offscreen_rendering_mode) {
1911 case ORM_FBO:
1912 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1913 break;
1915 case ORM_BACKBUFFER:
1917 if (context_get_current()->aux_buffers > 0)
1919 TRACE("Using auxilliary buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_AUX0;
1921 } else {
1922 TRACE("Using back buffer for offscreen rendering\n");
1923 This->offscreenBuffer = GL_BACK;
1928 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1929 LEAVE_GL();
1931 context_release(context);
1933 /* Clear the screen */
1934 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1935 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1936 0x00, 1.0f, 0);
1938 This->d3d_initialized = TRUE;
1940 if(wined3d_settings.logo) {
1941 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1943 This->highest_dirty_ps_const = 0;
1944 This->highest_dirty_vs_const = 0;
1945 return WINED3D_OK;
1947 err_out:
1948 HeapFree(GetProcessHeap(), 0, This->render_targets);
1949 HeapFree(GetProcessHeap(), 0, This->swapchains);
1950 This->NumberOfSwapChains = 0;
1951 if(This->palettes) {
1952 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1953 HeapFree(GetProcessHeap(), 0, This->palettes);
1955 This->NumberOfPalettes = 0;
1956 if(swapchain) {
1957 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1959 if(This->stateBlock) {
1960 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1961 This->stateBlock = NULL;
1963 if (This->blit_priv) {
1964 This->blitter->free_private(iface);
1966 if (This->fragment_priv) {
1967 This->frag_pipe->free_private(iface);
1969 if (This->shader_priv) {
1970 This->shader_backend->shader_free_private(iface);
1972 return hr;
1975 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1976 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1979 IWineD3DSwapChainImpl *swapchain = NULL;
1980 HRESULT hr;
1982 /* Setup the implicit swapchain */
1983 TRACE("Creating implicit swapchain\n");
1984 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1985 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1986 if (FAILED(hr))
1988 WARN("Failed to create implicit swapchain\n");
1989 goto err_out;
1992 This->NumberOfSwapChains = 1;
1993 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1994 if(!This->swapchains) {
1995 ERR("Out of memory!\n");
1996 goto err_out;
1998 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1999 return WINED3D_OK;
2001 err_out:
2002 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2003 return hr;
2006 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2008 IWineD3DResource_UnLoad(resource);
2009 IWineD3DResource_Release(resource);
2010 return WINED3D_OK;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2014 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 const struct wined3d_gl_info *gl_info;
2018 struct wined3d_context *context;
2019 int sampler;
2020 UINT i;
2021 TRACE("(%p)\n", This);
2023 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2025 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2026 * it was created. Thus make sure a context is active for the glDelete* calls
2028 context = context_acquire(This, NULL);
2029 gl_info = context->gl_info;
2031 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2033 /* Unload resources */
2034 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2036 TRACE("Deleting high order patches\n");
2037 for(i = 0; i < PATCHMAP_SIZE; i++) {
2038 struct list *e1, *e2;
2039 struct WineD3DRectPatch *patch;
2040 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2041 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2042 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2046 /* Delete the mouse cursor texture */
2047 if(This->cursorTexture) {
2048 ENTER_GL();
2049 glDeleteTextures(1, &This->cursorTexture);
2050 LEAVE_GL();
2051 This->cursorTexture = 0;
2054 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2055 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2057 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2058 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2061 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2062 * private data, it might contain opengl pointers
2064 if(This->depth_blt_texture) {
2065 ENTER_GL();
2066 glDeleteTextures(1, &This->depth_blt_texture);
2067 LEAVE_GL();
2068 This->depth_blt_texture = 0;
2070 if (This->depth_blt_rb) {
2071 ENTER_GL();
2072 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2073 LEAVE_GL();
2074 This->depth_blt_rb = 0;
2075 This->depth_blt_rb_w = 0;
2076 This->depth_blt_rb_h = 0;
2079 /* Release the update stateblock */
2080 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2081 if(This->updateStateBlock != This->stateBlock)
2082 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2084 This->updateStateBlock = NULL;
2086 { /* because were not doing proper internal refcounts releasing the primary state block
2087 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2088 to set this->stateBlock = NULL; first */
2089 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2090 This->stateBlock = NULL;
2092 /* Release the stateblock */
2093 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2094 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2098 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2099 This->blitter->free_private(iface);
2100 This->frag_pipe->free_private(iface);
2101 This->shader_backend->shader_free_private(iface);
2103 /* Release the buffers (with sanity checks)*/
2104 if (This->onscreen_depth_stencil)
2106 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2107 This->onscreen_depth_stencil = NULL;
2110 if (This->depth_stencil)
2112 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2114 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2116 This->depth_stencil = NULL;
2117 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2118 && ds != This->auto_depth_stencil)
2120 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2124 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2125 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2127 TRACE("Setting rendertarget to NULL\n");
2128 This->render_targets[0] = NULL;
2130 if (This->auto_depth_stencil)
2132 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2134 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2136 This->auto_depth_stencil = NULL;
2139 context_release(context);
2141 for(i=0; i < This->NumberOfSwapChains; i++) {
2142 TRACE("Releasing the implicit swapchain %d\n", i);
2143 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2144 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2148 HeapFree(GetProcessHeap(), 0, This->swapchains);
2149 This->swapchains = NULL;
2150 This->NumberOfSwapChains = 0;
2152 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2153 HeapFree(GetProcessHeap(), 0, This->palettes);
2154 This->palettes = NULL;
2155 This->NumberOfPalettes = 0;
2157 HeapFree(GetProcessHeap(), 0, This->render_targets);
2158 This->render_targets = NULL;
2160 This->d3d_initialized = FALSE;
2162 return WINED3D_OK;
2165 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2167 unsigned int i;
2169 for(i=0; i < This->NumberOfSwapChains; i++) {
2170 TRACE("Releasing the implicit swapchain %d\n", i);
2171 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2172 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2176 HeapFree(GetProcessHeap(), 0, This->swapchains);
2177 This->swapchains = NULL;
2178 This->NumberOfSwapChains = 0;
2179 return WINED3D_OK;
2182 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2183 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2184 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2186 * There is no way to deactivate thread safety once it is enabled.
2188 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2191 /*For now just store the flag(needed in case of ddraw) */
2192 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2195 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2196 const WINED3DDISPLAYMODE* pMode) {
2197 DEVMODEW devmode;
2198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2199 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2200 LONG ret;
2201 RECT clip_rc;
2203 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2205 /* Resize the screen even without a window:
2206 * The app could have unset it with SetCooperativeLevel, but not called
2207 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2208 * but we don't have any hwnd
2211 memset(&devmode, 0, sizeof(devmode));
2212 devmode.dmSize = sizeof(devmode);
2213 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2214 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2215 devmode.dmPelsWidth = pMode->Width;
2216 devmode.dmPelsHeight = pMode->Height;
2218 devmode.dmDisplayFrequency = pMode->RefreshRate;
2219 if (pMode->RefreshRate)
2220 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2222 /* Only change the mode if necessary */
2223 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2224 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2225 return WINED3D_OK;
2227 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2228 if (ret != DISP_CHANGE_SUCCESSFUL)
2230 if (devmode.dmDisplayFrequency)
2232 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2233 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2234 devmode.dmDisplayFrequency = 0;
2235 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2237 if(ret != DISP_CHANGE_SUCCESSFUL) {
2238 return WINED3DERR_NOTAVAILABLE;
2242 /* Store the new values */
2243 This->ddraw_width = pMode->Width;
2244 This->ddraw_height = pMode->Height;
2245 This->ddraw_format = pMode->Format;
2247 /* And finally clip mouse to our screen */
2248 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2249 ClipCursor(&clip_rc);
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2256 *ppD3D = This->wined3d;
2257 TRACE("Returning %p.\n", *ppD3D);
2258 IWineD3D_AddRef(*ppD3D);
2259 return WINED3D_OK;
2262 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2265 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2266 (This->adapter->TextureRam/(1024*1024)),
2267 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2268 /* return simulated texture memory left */
2269 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2272 /*****
2273 * Get / Set Stream Source
2274 *****/
2275 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2276 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2279 struct wined3d_stream_state *stream;
2280 IWineD3DBuffer *oldSrc;
2282 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2283 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2285 if (StreamNumber >= MAX_STREAMS) {
2286 WARN("Stream out of range %d\n", StreamNumber);
2287 return WINED3DERR_INVALIDCALL;
2288 } else if(OffsetInBytes & 0x3) {
2289 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2290 return WINED3DERR_INVALIDCALL;
2293 stream = &This->updateStateBlock->state.streams[StreamNumber];
2294 oldSrc = (IWineD3DBuffer *)stream->buffer;
2296 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2298 if (oldSrc == pStreamData
2299 && stream->stride == Stride
2300 && stream->offset == OffsetInBytes)
2302 TRACE("Application is setting the old values over, nothing to do\n");
2303 return WINED3D_OK;
2306 stream->buffer = (struct wined3d_buffer *)pStreamData;
2307 if (pStreamData)
2309 stream->stride = Stride;
2310 stream->offset = OffsetInBytes;
2313 /* Handle recording of state blocks */
2314 if (This->isRecordingState) {
2315 TRACE("Recording... not performing anything\n");
2316 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2317 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2318 return WINED3D_OK;
2321 if (pStreamData)
2323 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2324 IWineD3DBuffer_AddRef(pStreamData);
2326 if (oldSrc)
2328 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2329 IWineD3DBuffer_Release(oldSrc);
2332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2334 return WINED3D_OK;
2337 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2338 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2341 struct wined3d_stream_state *stream;
2343 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2344 iface, StreamNumber, pStream, pOffset, pStride);
2346 if (StreamNumber >= MAX_STREAMS)
2348 WARN("Stream out of range %d\n", StreamNumber);
2349 return WINED3DERR_INVALIDCALL;
2352 stream = &This->stateBlock->state.streams[StreamNumber];
2353 *pStream = (IWineD3DBuffer *)stream->buffer;
2354 *pStride = stream->stride;
2355 if (pOffset) *pOffset = stream->offset;
2357 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2359 return WINED3D_OK;
2362 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 struct wined3d_stream_state *stream;
2365 UINT oldFlags, oldFreq;
2367 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2369 /* Verify input at least in d3d9 this is invalid. */
2370 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2372 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2373 return WINED3DERR_INVALIDCALL;
2375 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2377 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2378 return WINED3DERR_INVALIDCALL;
2380 if (!Divider)
2382 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2383 return WINED3DERR_INVALIDCALL;
2386 stream = &This->updateStateBlock->state.streams[StreamNumber];
2387 oldFlags = stream->flags;
2388 oldFreq = stream->frequency;
2390 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2391 stream->frequency = Divider & 0x7FFFFF;
2393 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2395 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2398 return WINED3D_OK;
2401 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 struct wined3d_stream_state *stream;
2405 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2407 stream = &This->updateStateBlock->state.streams[StreamNumber];
2408 *Divider = stream->flags | stream->frequency;
2410 TRACE("Returning %#x.\n", *Divider);
2412 return WINED3D_OK;
2415 /*****
2416 * Get / Set & Multiply Transform
2417 *****/
2418 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 /* Most of this routine, comments included copied from ddraw tree initially: */
2422 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2424 /* Handle recording of state blocks */
2425 if (This->isRecordingState) {
2426 TRACE("Recording... not performing anything\n");
2427 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2428 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2429 return WINED3D_OK;
2433 * If the new matrix is the same as the current one,
2434 * we cut off any further processing. this seems to be a reasonable
2435 * optimization because as was noticed, some apps (warcraft3 for example)
2436 * tend towards setting the same matrix repeatedly for some reason.
2438 * From here on we assume that the new matrix is different, wherever it matters.
2440 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2442 TRACE("The app is setting the same matrix over again\n");
2443 return WINED3D_OK;
2445 else
2447 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2451 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2452 where ViewMat = Camera space, WorldMat = world space.
2454 In OpenGL, camera and world space is combined into GL_MODELVIEW
2455 matrix. The Projection matrix stay projection matrix.
2458 /* Capture the times we can just ignore the change for now */
2459 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2460 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2461 /* Handled by the state manager */
2464 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2467 return WINED3D_OK;
2471 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2472 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2474 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2476 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2478 *matrix = device->stateBlock->state.transforms[state];
2480 return WINED3D_OK;
2483 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2484 const WINED3DMATRIX *mat = NULL;
2485 WINED3DMATRIX temp;
2487 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2488 * below means it will be recorded in a state block change, but it
2489 * works regardless where it is recorded.
2490 * If this is found to be wrong, change to StateBlock.
2492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2493 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2495 if (State <= HIGHEST_TRANSFORMSTATE)
2497 mat = &This->updateStateBlock->state.transforms[State];
2499 else
2501 FIXME("Unhandled transform state!!\n");
2504 multiply_matrix(&temp, mat, pMatrix);
2506 /* Apply change via set transform - will reapply to eg. lights this way */
2507 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2510 /*****
2511 * Get / Set Light
2512 *****/
2513 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2514 you can reference any indexes you want as long as that number max are enabled at any
2515 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2516 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2517 but when recording, just build a chain pretty much of commands to be replayed. */
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2520 float rho;
2521 struct wined3d_light_info *object = NULL;
2522 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2523 struct list *e;
2525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2528 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2529 * the gl driver.
2531 if(!pLight) {
2532 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2533 return WINED3DERR_INVALIDCALL;
2536 switch(pLight->Type) {
2537 case WINED3DLIGHT_POINT:
2538 case WINED3DLIGHT_SPOT:
2539 case WINED3DLIGHT_PARALLELPOINT:
2540 case WINED3DLIGHT_GLSPOT:
2541 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2542 * most wanted
2544 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2546 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2547 return WINED3DERR_INVALIDCALL;
2549 break;
2551 case WINED3DLIGHT_DIRECTIONAL:
2552 /* Ignores attenuation */
2553 break;
2555 default:
2556 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2557 return WINED3DERR_INVALIDCALL;
2560 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2562 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2563 if(object->OriginalIndex == Index) break;
2564 object = NULL;
2567 if(!object) {
2568 TRACE("Adding new light\n");
2569 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2570 if(!object) {
2571 ERR("Out of memory error when allocating a light\n");
2572 return E_OUTOFMEMORY;
2574 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2575 object->glIndex = -1;
2576 object->OriginalIndex = Index;
2579 /* Initialize the object */
2580 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,
2581 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2582 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2583 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2584 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2585 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2586 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2588 /* Save away the information */
2589 object->OriginalParms = *pLight;
2591 switch (pLight->Type) {
2592 case WINED3DLIGHT_POINT:
2593 /* Position */
2594 object->lightPosn[0] = pLight->Position.x;
2595 object->lightPosn[1] = pLight->Position.y;
2596 object->lightPosn[2] = pLight->Position.z;
2597 object->lightPosn[3] = 1.0f;
2598 object->cutoff = 180.0f;
2599 /* FIXME: Range */
2600 break;
2602 case WINED3DLIGHT_DIRECTIONAL:
2603 /* Direction */
2604 object->lightPosn[0] = -pLight->Direction.x;
2605 object->lightPosn[1] = -pLight->Direction.y;
2606 object->lightPosn[2] = -pLight->Direction.z;
2607 object->lightPosn[3] = 0.0f;
2608 object->exponent = 0.0f;
2609 object->cutoff = 180.0f;
2610 break;
2612 case WINED3DLIGHT_SPOT:
2613 /* Position */
2614 object->lightPosn[0] = pLight->Position.x;
2615 object->lightPosn[1] = pLight->Position.y;
2616 object->lightPosn[2] = pLight->Position.z;
2617 object->lightPosn[3] = 1.0f;
2619 /* Direction */
2620 object->lightDirn[0] = pLight->Direction.x;
2621 object->lightDirn[1] = pLight->Direction.y;
2622 object->lightDirn[2] = pLight->Direction.z;
2623 object->lightDirn[3] = 1.0f;
2626 * opengl-ish and d3d-ish spot lights use too different models for the
2627 * light "intensity" as a function of the angle towards the main light direction,
2628 * so we only can approximate very roughly.
2629 * however spot lights are rather rarely used in games (if ever used at all).
2630 * furthermore if still used, probably nobody pays attention to such details.
2632 if (!pLight->Falloff)
2634 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2635 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2636 * will always be 1.0 for both of them, and we don't have to care for the
2637 * rest of the rather complex calculation
2639 object->exponent = 0.0f;
2640 } else {
2641 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2642 if (rho < 0.0001f) rho = 0.0001f;
2643 object->exponent = -0.3f/logf(cosf(rho/2));
2645 if (object->exponent > 128.0f)
2647 object->exponent = 128.0f;
2649 object->cutoff = (float) (pLight->Phi*90/M_PI);
2651 /* FIXME: Range */
2652 break;
2654 default:
2655 FIXME("Unrecognized light type %d\n", pLight->Type);
2658 /* Update the live definitions if the light is currently assigned a glIndex */
2659 if (object->glIndex != -1 && !This->isRecordingState) {
2660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2662 return WINED3D_OK;
2665 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2667 struct wined3d_light_info *lightInfo = NULL;
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2670 struct list *e;
2671 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2673 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2675 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2676 if(lightInfo->OriginalIndex == Index) break;
2677 lightInfo = NULL;
2680 if (!lightInfo)
2682 TRACE("Light information requested but light not defined\n");
2683 return WINED3DERR_INVALIDCALL;
2686 *pLight = lightInfo->OriginalParms;
2687 return WINED3D_OK;
2690 /*****
2691 * Get / Set Light Enable
2692 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2696 struct wined3d_light_info *lightInfo = NULL;
2697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2699 struct list *e;
2700 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2702 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2704 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2705 if(lightInfo->OriginalIndex == Index) break;
2706 lightInfo = NULL;
2708 TRACE("Found light: %p\n", lightInfo);
2710 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2711 if (!lightInfo)
2713 TRACE("Light enabled requested but light not defined, so defining one!\n");
2714 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2716 /* Search for it again! Should be fairly quick as near head of list */
2717 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2719 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2720 if(lightInfo->OriginalIndex == Index) break;
2721 lightInfo = NULL;
2723 if (!lightInfo)
2725 FIXME("Adding default lights has failed dismally\n");
2726 return WINED3DERR_INVALIDCALL;
2730 if(!Enable) {
2731 if(lightInfo->glIndex != -1) {
2732 if(!This->isRecordingState) {
2733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2736 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2737 lightInfo->glIndex = -1;
2738 } else {
2739 TRACE("Light already disabled, nothing to do\n");
2741 lightInfo->enabled = FALSE;
2742 } else {
2743 lightInfo->enabled = TRUE;
2744 if (lightInfo->glIndex != -1) {
2745 /* nop */
2746 TRACE("Nothing to do as light was enabled\n");
2747 } else {
2748 int i;
2749 /* Find a free gl light */
2750 for (i = 0; i < This->maxConcurrentLights; ++i)
2752 if (!This->updateStateBlock->state.lights[i])
2754 This->updateStateBlock->state.lights[i] = lightInfo;
2755 lightInfo->glIndex = i;
2756 break;
2759 if(lightInfo->glIndex == -1) {
2760 /* Our tests show that Windows returns D3D_OK in this situation, even with
2761 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2762 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2763 * as well for those lights.
2765 * TODO: Test how this affects rendering
2767 WARN("Too many concurrently active lights\n");
2768 return WINED3D_OK;
2771 /* i == lightInfo->glIndex */
2772 if(!This->isRecordingState) {
2773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2778 return WINED3D_OK;
2781 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2783 struct wined3d_light_info *lightInfo = NULL;
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 struct list *e;
2786 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2787 TRACE("(%p) : for idx(%d)\n", This, Index);
2789 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2791 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2792 if(lightInfo->OriginalIndex == Index) break;
2793 lightInfo = NULL;
2796 if (!lightInfo)
2798 TRACE("Light enabled state requested but light not defined\n");
2799 return WINED3DERR_INVALIDCALL;
2801 /* true is 128 according to SetLightEnable */
2802 *pEnable = lightInfo->enabled ? 128 : 0;
2803 return WINED3D_OK;
2806 /*****
2807 * Get / Set Clip Planes
2808 *****/
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2813 /* Validate Index */
2814 if (Index >= This->adapter->gl_info.limits.clipplanes)
2816 TRACE("Application has requested clipplane this device doesn't support\n");
2817 return WINED3DERR_INVALIDCALL;
2820 This->updateStateBlock->changed.clipplane |= 1 << Index;
2822 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2823 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2824 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2825 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2827 TRACE("Application is setting old values over, nothing to do\n");
2828 return WINED3D_OK;
2831 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2832 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2833 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2834 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2836 /* Handle recording of state blocks */
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2839 return WINED3D_OK;
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2844 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 TRACE("(%p) : for idx %d\n", This, Index);
2851 /* Validate Index */
2852 if (Index >= This->adapter->gl_info.limits.clipplanes)
2854 TRACE("Application has requested clipplane this device doesn't support\n");
2855 return WINED3DERR_INVALIDCALL;
2858 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2859 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2860 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2861 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2862 return WINED3D_OK;
2865 /*****
2866 * Get / Set Clip Plane Status
2867 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2868 *****/
2869 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 FIXME("(%p) : stub\n", This);
2873 if (!pClipStatus)
2874 return WINED3DERR_INVALIDCALL;
2876 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2877 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2878 return WINED3D_OK;
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2883 FIXME("(%p) : stub\n", This);
2885 if (!pClipStatus)
2886 return WINED3DERR_INVALIDCALL;
2888 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2889 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2890 return WINED3D_OK;
2893 /*****
2894 * Get / Set Material
2895 *****/
2896 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2899 This->updateStateBlock->changed.material = TRUE;
2900 This->updateStateBlock->state.material = *pMaterial;
2902 /* Handle recording of state blocks */
2903 if (This->isRecordingState) {
2904 TRACE("Recording... not performing anything\n");
2905 return WINED3D_OK;
2908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2909 return WINED3D_OK;
2912 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 *pMaterial = This->updateStateBlock->state.material;
2915 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2916 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2917 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2918 pMaterial->Ambient.b, pMaterial->Ambient.a);
2919 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2920 pMaterial->Specular.b, pMaterial->Specular.a);
2921 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2922 pMaterial->Emissive.b, pMaterial->Emissive.a);
2923 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2925 return WINED3D_OK;
2928 /*****
2929 * Get / Set Indices
2930 *****/
2931 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2932 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 IWineD3DBuffer *oldIdxs;
2937 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2938 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2940 This->updateStateBlock->changed.indices = TRUE;
2941 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2942 This->updateStateBlock->state.index_format = fmt;
2944 /* Handle recording of state blocks */
2945 if (This->isRecordingState) {
2946 TRACE("Recording... not performing anything\n");
2947 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2948 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2949 return WINED3D_OK;
2952 if(oldIdxs != pIndexData) {
2953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2954 if(pIndexData) {
2955 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2956 IWineD3DBuffer_AddRef(pIndexData);
2958 if(oldIdxs) {
2959 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2960 IWineD3DBuffer_Release(oldIdxs);
2964 return WINED3D_OK;
2967 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2973 /* up ref count on ppindexdata */
2974 if (*ppIndexData) {
2975 IWineD3DBuffer_AddRef(*ppIndexData);
2976 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2977 }else{
2978 TRACE("(%p) No index data set\n", This);
2980 TRACE("Returning %p\n", *ppIndexData);
2982 return WINED3D_OK;
2985 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2986 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 TRACE("(%p)->(%d)\n", This, BaseIndex);
2990 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2992 TRACE("Application is setting the old value over, nothing to do\n");
2993 return WINED3D_OK;
2996 This->updateStateBlock->state.base_vertex_index = BaseIndex;
2998 if (This->isRecordingState) {
2999 TRACE("Recording... not performing anything\n");
3000 return WINED3D_OK;
3002 /* The base vertex index affects the stream sources */
3003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3004 return WINED3D_OK;
3007 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009 TRACE("(%p) : base_index %p\n", This, base_index);
3011 *base_index = This->stateBlock->state.base_vertex_index;
3013 TRACE("Returning %u\n", *base_index);
3015 return WINED3D_OK;
3018 /*****
3019 * Get / Set Viewports
3020 *****/
3021 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 TRACE("(%p)\n", This);
3025 This->updateStateBlock->changed.viewport = TRUE;
3026 This->updateStateBlock->state.viewport = *pViewport;
3028 /* Handle recording of state blocks */
3029 if (This->isRecordingState) {
3030 TRACE("Recording... not performing anything\n");
3031 return WINED3D_OK;
3034 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3035 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3038 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 TRACE("(%p)\n", This);
3045 *pViewport = This->stateBlock->state.viewport;
3046 return WINED3D_OK;
3049 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3050 WINED3DRENDERSTATETYPE State, DWORD Value)
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 DWORD oldValue = This->stateBlock->state.render_states[State];
3055 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3057 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3058 This->updateStateBlock->state.render_states[State] = Value;
3060 /* Handle recording of state blocks */
3061 if (This->isRecordingState) {
3062 TRACE("Recording... not performing anything\n");
3063 return WINED3D_OK;
3066 /* Compared here and not before the assignment to allow proper stateblock recording */
3067 if(Value == oldValue) {
3068 TRACE("Application is setting the old value over, nothing to do\n");
3069 } else {
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3077 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3083 *pValue = This->stateBlock->state.render_states[State];
3084 return WINED3D_OK;
3087 /*****
3088 * Get / Set Sampler States
3089 * TODO: Verify against dx9 definitions
3090 *****/
3092 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 DWORD oldValue;
3096 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3097 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3099 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3100 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3103 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3105 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3106 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3109 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3110 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3111 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3113 /* Handle recording of state blocks */
3114 if (This->isRecordingState) {
3115 TRACE("Recording... not performing anything\n");
3116 return WINED3D_OK;
3119 if(oldValue == Value) {
3120 TRACE("Application is setting the old value over, nothing to do\n");
3121 return WINED3D_OK;
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3133 This, Sampler, debug_d3dsamplerstate(Type), Type);
3135 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3136 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3139 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3141 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3142 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3144 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3145 TRACE("(%p) : Returning %#x\n", This, *Value);
3147 return WINED3D_OK;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 This->updateStateBlock->changed.scissorRect = TRUE;
3154 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3156 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3157 return WINED3D_OK;
3159 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3161 if(This->isRecordingState) {
3162 TRACE("Recording... not performing anything\n");
3163 return WINED3D_OK;
3166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3168 return WINED3D_OK;
3171 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 *pRect = This->updateStateBlock->state.scissor_rect;
3175 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3176 return WINED3D_OK;
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3181 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3183 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3185 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3186 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3188 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3189 This->updateStateBlock->changed.vertexDecl = TRUE;
3191 if (This->isRecordingState) {
3192 TRACE("Recording... not performing anything\n");
3193 return WINED3D_OK;
3194 } else if(pDecl == oldDecl) {
3195 /* Checked after the assignment to allow proper stateblock recording */
3196 TRACE("Application is setting the old declaration over, nothing to do\n");
3197 return WINED3D_OK;
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3201 return WINED3D_OK;
3204 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3209 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3210 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3211 return WINED3D_OK;
3214 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3219 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3220 This->updateStateBlock->changed.vertexShader = TRUE;
3222 if (This->isRecordingState) {
3223 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3224 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3225 TRACE("Recording... not performing anything\n");
3226 return WINED3D_OK;
3227 } else if(oldShader == pShader) {
3228 /* Checked here to allow proper stateblock recording */
3229 TRACE("App is setting the old shader over, nothing to do\n");
3230 return WINED3D_OK;
3233 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3234 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3235 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3239 return WINED3D_OK;
3242 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3244 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3245 IWineD3DVertexShader *shader;
3247 TRACE("iface %p.\n", iface);
3249 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3250 if (shader) IWineD3DVertexShader_AddRef(shader);
3252 TRACE("Returning %p.\n", shader);
3253 return shader;
3256 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3257 IWineD3DDevice *iface,
3258 UINT start,
3259 CONST BOOL *srcData,
3260 UINT count) {
3262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3265 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3266 iface, srcData, start, count);
3268 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3270 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3271 for (i = 0; i < cnt; i++)
3272 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3274 for (i = start; i < cnt + start; ++i) {
3275 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3278 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3280 return WINED3D_OK;
3283 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3284 IWineD3DDevice *iface,
3285 UINT start,
3286 BOOL *dstData,
3287 UINT count) {
3289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 int cnt = min(count, MAX_CONST_B - start);
3292 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3293 iface, dstData, start, count);
3295 if (!dstData || cnt < 0)
3296 return WINED3DERR_INVALIDCALL;
3298 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3299 return WINED3D_OK;
3302 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3303 IWineD3DDevice *iface,
3304 UINT start,
3305 CONST int *srcData,
3306 UINT count) {
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3311 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3312 iface, srcData, start, count);
3314 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3316 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3317 for (i = 0; i < cnt; i++)
3318 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3319 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3321 for (i = start; i < cnt + start; ++i) {
3322 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3325 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3327 return WINED3D_OK;
3330 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3331 IWineD3DDevice *iface,
3332 UINT start,
3333 int *dstData,
3334 UINT count) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3337 int cnt = min(count, MAX_CONST_I - start);
3339 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3340 iface, dstData, start, count);
3342 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3346 return WINED3D_OK;
3349 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3350 IWineD3DDevice *iface,
3351 UINT start,
3352 CONST float *srcData,
3353 UINT count) {
3355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 UINT i;
3358 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3359 iface, srcData, start, count);
3361 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3362 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3363 return WINED3DERR_INVALIDCALL;
3365 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3366 if(TRACE_ON(d3d)) {
3367 for (i = 0; i < count; i++)
3368 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3369 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3372 if (!This->isRecordingState)
3374 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3378 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3379 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3381 return WINED3D_OK;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3385 IWineD3DDevice *iface,
3386 UINT start,
3387 float *dstData,
3388 UINT count) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 int cnt = min(count, This->d3d_vshader_constantF - start);
3393 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3394 iface, dstData, start, count);
3396 if (!dstData || cnt < 0)
3397 return WINED3DERR_INVALIDCALL;
3399 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3400 return WINED3D_OK;
3403 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3404 DWORD i;
3405 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3411 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3413 DWORD i = This->rev_tex_unit_map[unit];
3414 DWORD j = This->texUnitMap[stage];
3416 This->texUnitMap[stage] = unit;
3417 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3419 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3422 This->rev_tex_unit_map[unit] = stage;
3423 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3425 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3429 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3430 int i;
3432 This->fixed_function_usage_map = 0;
3433 for (i = 0; i < MAX_TEXTURES; ++i)
3435 const struct wined3d_state *state = &This->stateBlock->state;
3436 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3437 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3438 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3439 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3440 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3441 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3442 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3443 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3445 if (color_op == WINED3DTOP_DISABLE) {
3446 /* Not used, and disable higher stages */
3447 break;
3450 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3451 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3452 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3453 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3454 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3455 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3456 This->fixed_function_usage_map |= (1 << i);
3459 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3460 This->fixed_function_usage_map |= (1 << (i + 1));
3465 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3467 unsigned int i, tex;
3468 WORD ffu_map;
3470 device_update_fixed_function_usage_map(This);
3471 ffu_map = This->fixed_function_usage_map;
3473 if (This->max_ffp_textures == gl_info->limits.texture_stages
3474 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3476 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3478 if (!(ffu_map & 1)) continue;
3480 if (This->texUnitMap[i] != i) {
3481 device_map_stage(This, i, i);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3483 markTextureStagesDirty(This, i);
3486 return;
3489 /* Now work out the mapping */
3490 tex = 0;
3491 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3493 if (!(ffu_map & 1)) continue;
3495 if (This->texUnitMap[i] != tex) {
3496 device_map_stage(This, i, tex);
3497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3498 markTextureStagesDirty(This, i);
3501 ++tex;
3505 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3507 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3508 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3509 unsigned int i;
3511 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3512 if (sampler_type[i] && This->texUnitMap[i] != i)
3514 device_map_stage(This, i, i);
3515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3516 if (i < gl_info->limits.texture_stages)
3518 markTextureStagesDirty(This, i);
3524 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3525 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3527 DWORD current_mapping = This->rev_tex_unit_map[unit];
3529 /* Not currently used */
3530 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3532 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3533 /* Used by a fragment sampler */
3535 if (!pshader_sampler_tokens) {
3536 /* No pixel shader, check fixed function */
3537 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3540 /* Pixel shader, check the shader's sampler map */
3541 return !pshader_sampler_tokens[current_mapping];
3544 /* Used by a vertex sampler */
3545 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3548 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3550 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3551 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3552 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3553 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3554 int i;
3556 if (ps)
3558 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3560 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3561 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3562 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3565 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3566 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3567 if (vshader_sampler_type[i])
3569 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3571 /* Already mapped somewhere */
3572 continue;
3575 while (start >= 0) {
3576 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3578 device_map_stage(This, vsampler_idx, start);
3579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3581 --start;
3582 break;
3585 --start;
3591 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3593 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3594 const struct wined3d_state *state = &This->stateBlock->state;
3595 BOOL vs = use_vs(state);
3596 BOOL ps = use_ps(state);
3598 * Rules are:
3599 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3600 * that would be really messy and require shader recompilation
3601 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3602 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3604 if (ps) device_map_psamplers(This, gl_info);
3605 else device_map_fixed_function_samplers(This, gl_info);
3607 if (vs) device_map_vsamplers(This, ps, gl_info);
3610 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3614 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3615 This->updateStateBlock->changed.pixelShader = TRUE;
3617 /* Handle recording of state blocks */
3618 if (This->isRecordingState) {
3619 TRACE("Recording... not performing anything\n");
3622 if (This->isRecordingState) {
3623 TRACE("Recording... not performing anything\n");
3624 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3625 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3626 return WINED3D_OK;
3629 if(pShader == oldShader) {
3630 TRACE("App is setting the old pixel shader over, nothing to do\n");
3631 return WINED3D_OK;
3634 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3635 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3637 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3640 return WINED3D_OK;
3643 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3645 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3646 IWineD3DPixelShader *shader;
3648 TRACE("iface %p.\n", iface);
3650 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3651 if (shader) IWineD3DPixelShader_AddRef(shader);
3653 TRACE("Returning %p.\n", shader);
3654 return shader;
3657 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3658 IWineD3DDevice *iface,
3659 UINT start,
3660 CONST BOOL *srcData,
3661 UINT count) {
3663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3664 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3666 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3667 iface, srcData, start, count);
3669 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3671 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3672 for (i = 0; i < cnt; i++)
3673 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3675 for (i = start; i < cnt + start; ++i) {
3676 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3679 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3681 return WINED3D_OK;
3684 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3685 IWineD3DDevice *iface,
3686 UINT start,
3687 BOOL *dstData,
3688 UINT count) {
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 int cnt = min(count, MAX_CONST_B - start);
3693 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3694 iface, dstData, start, count);
3696 if (!dstData || cnt < 0)
3697 return WINED3DERR_INVALIDCALL;
3699 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3700 return WINED3D_OK;
3703 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3704 IWineD3DDevice *iface,
3705 UINT start,
3706 CONST int *srcData,
3707 UINT count) {
3709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3710 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3712 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3713 iface, srcData, start, count);
3715 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3717 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3718 for (i = 0; i < cnt; i++)
3719 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3720 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3722 for (i = start; i < cnt + start; ++i) {
3723 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3726 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3728 return WINED3D_OK;
3731 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3732 IWineD3DDevice *iface,
3733 UINT start,
3734 int *dstData,
3735 UINT count) {
3737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3738 int cnt = min(count, MAX_CONST_I - start);
3740 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3741 iface, dstData, start, count);
3743 if (!dstData || cnt < 0)
3744 return WINED3DERR_INVALIDCALL;
3746 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3747 return WINED3D_OK;
3750 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3751 IWineD3DDevice *iface,
3752 UINT start,
3753 CONST float *srcData,
3754 UINT count) {
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 UINT i;
3759 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3760 iface, srcData, start, count);
3762 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3763 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3767 if(TRACE_ON(d3d)) {
3768 for (i = 0; i < count; i++)
3769 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3770 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3773 if (!This->isRecordingState)
3775 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3779 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3780 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3782 return WINED3D_OK;
3785 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3786 IWineD3DDevice *iface,
3787 UINT start,
3788 float *dstData,
3789 UINT count) {
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 int cnt = min(count, This->d3d_pshader_constantF - start);
3794 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3795 iface, dstData, start, count);
3797 if (!dstData || cnt < 0)
3798 return WINED3DERR_INVALIDCALL;
3800 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3801 return WINED3D_OK;
3804 /* Context activation is done by the caller. */
3805 /* Do not call while under the GL lock. */
3806 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3807 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3808 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3809 DWORD DestFVF)
3811 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3812 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3813 unsigned int i;
3814 WINED3DVIEWPORT vp;
3815 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3816 BOOL doClip;
3817 DWORD numTextures;
3819 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3821 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3824 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3826 ERR("Source has no position mask\n");
3827 return WINED3DERR_INVALIDCALL;
3830 if (!dest->resource.allocatedMemory)
3831 buffer_get_sysmem(dest, gl_info);
3833 /* Get a pointer into the destination vbo(create one if none exists) and
3834 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3836 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3838 dest->flags |= WINED3D_BUFFER_CREATEBO;
3839 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3842 if (dest->buffer_object)
3844 unsigned char extrabytes = 0;
3845 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3846 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3847 * this may write 4 extra bytes beyond the area that should be written
3849 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3850 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3851 if(!dest_conv_addr) {
3852 ERR("Out of memory\n");
3853 /* Continue without storing converted vertices */
3855 dest_conv = dest_conv_addr;
3858 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3860 static BOOL warned = FALSE;
3862 * The clipping code is not quite correct. Some things need
3863 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3864 * so disable clipping for now.
3865 * (The graphics in Half-Life are broken, and my processvertices
3866 * test crashes with IDirect3DDevice3)
3867 doClip = TRUE;
3869 doClip = FALSE;
3870 if(!warned) {
3871 warned = TRUE;
3872 FIXME("Clipping is broken and disabled for now\n");
3874 } else doClip = FALSE;
3875 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3877 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3878 WINED3DTS_VIEW,
3879 &view_mat);
3880 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3881 WINED3DTS_PROJECTION,
3882 &proj_mat);
3883 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3884 WINED3DTS_WORLDMATRIX(0),
3885 &world_mat);
3887 TRACE("View mat:\n");
3888 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);
3889 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);
3890 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);
3891 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);
3893 TRACE("Proj mat:\n");
3894 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);
3895 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);
3896 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);
3897 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);
3899 TRACE("World mat:\n");
3900 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);
3901 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);
3902 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);
3903 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);
3905 /* Get the viewport */
3906 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3907 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3908 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3910 multiply_matrix(&mat,&view_mat,&world_mat);
3911 multiply_matrix(&mat,&proj_mat,&mat);
3913 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3915 for (i = 0; i < dwCount; i+= 1) {
3916 unsigned int tex_index;
3918 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3919 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3920 /* The position first */
3921 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3922 const float *p = (const float *)(element->data + i * element->stride);
3923 float x, y, z, rhw;
3924 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3926 /* Multiplication with world, view and projection matrix */
3927 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);
3928 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);
3929 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);
3930 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);
3932 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3934 /* WARNING: The following things are taken from d3d7 and were not yet checked
3935 * against d3d8 or d3d9!
3938 /* Clipping conditions: From msdn
3940 * A vertex is clipped if it does not match the following requirements
3941 * -rhw < x <= rhw
3942 * -rhw < y <= rhw
3943 * 0 < z <= rhw
3944 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3946 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3947 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3951 if( !doClip ||
3952 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3953 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3954 ( rhw > eps ) ) ) {
3956 /* "Normal" viewport transformation (not clipped)
3957 * 1) The values are divided by rhw
3958 * 2) The y axis is negative, so multiply it with -1
3959 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3960 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3961 * 4) Multiply x with Width/2 and add Width/2
3962 * 5) The same for the height
3963 * 6) Add the viewpoint X and Y to the 2D coordinates and
3964 * The minimum Z value to z
3965 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3967 * Well, basically it's simply a linear transformation into viewport
3968 * coordinates
3971 x /= rhw;
3972 y /= rhw;
3973 z /= rhw;
3975 y *= -1;
3977 x *= vp.Width / 2;
3978 y *= vp.Height / 2;
3979 z *= vp.MaxZ - vp.MinZ;
3981 x += vp.Width / 2 + vp.X;
3982 y += vp.Height / 2 + vp.Y;
3983 z += vp.MinZ;
3985 rhw = 1 / rhw;
3986 } else {
3987 /* That vertex got clipped
3988 * Contrary to OpenGL it is not dropped completely, it just
3989 * undergoes a different calculation.
3991 TRACE("Vertex got clipped\n");
3992 x += rhw;
3993 y += rhw;
3995 x /= 2;
3996 y /= 2;
3998 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3999 * outside of the main vertex buffer memory. That needs some more
4000 * investigation...
4004 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4007 ( (float *) dest_ptr)[0] = x;
4008 ( (float *) dest_ptr)[1] = y;
4009 ( (float *) dest_ptr)[2] = z;
4010 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4012 dest_ptr += 3 * sizeof(float);
4014 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4015 dest_ptr += sizeof(float);
4018 if(dest_conv) {
4019 float w = 1 / rhw;
4020 ( (float *) dest_conv)[0] = x * w;
4021 ( (float *) dest_conv)[1] = y * w;
4022 ( (float *) dest_conv)[2] = z * w;
4023 ( (float *) dest_conv)[3] = w;
4025 dest_conv += 3 * sizeof(float);
4027 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4028 dest_conv += sizeof(float);
4032 if (DestFVF & WINED3DFVF_PSIZE) {
4033 dest_ptr += sizeof(DWORD);
4034 if(dest_conv) dest_conv += sizeof(DWORD);
4036 if (DestFVF & WINED3DFVF_NORMAL) {
4037 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4038 const float *normal = (const float *)(element->data + i * element->stride);
4039 /* AFAIK this should go into the lighting information */
4040 FIXME("Didn't expect the destination to have a normal\n");
4041 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4042 if(dest_conv) {
4043 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4047 if (DestFVF & WINED3DFVF_DIFFUSE) {
4048 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4049 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4050 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4052 static BOOL warned = FALSE;
4054 if(!warned) {
4055 ERR("No diffuse color in source, but destination has one\n");
4056 warned = TRUE;
4059 *( (DWORD *) dest_ptr) = 0xffffffff;
4060 dest_ptr += sizeof(DWORD);
4062 if(dest_conv) {
4063 *( (DWORD *) dest_conv) = 0xffffffff;
4064 dest_conv += sizeof(DWORD);
4067 else {
4068 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4069 if(dest_conv) {
4070 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4071 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4072 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4073 dest_conv += sizeof(DWORD);
4078 if (DestFVF & WINED3DFVF_SPECULAR)
4080 /* What's the color value in the feedback buffer? */
4081 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4082 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4083 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4085 static BOOL warned = FALSE;
4087 if(!warned) {
4088 ERR("No specular color in source, but destination has one\n");
4089 warned = TRUE;
4092 *( (DWORD *) dest_ptr) = 0xFF000000;
4093 dest_ptr += sizeof(DWORD);
4095 if(dest_conv) {
4096 *( (DWORD *) dest_conv) = 0xFF000000;
4097 dest_conv += sizeof(DWORD);
4100 else {
4101 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4102 if(dest_conv) {
4103 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4104 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4105 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4106 dest_conv += sizeof(DWORD);
4111 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4112 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4113 const float *tex_coord = (const float *)(element->data + i * element->stride);
4114 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4116 ERR("No source texture, but destination requests one\n");
4117 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4118 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4120 else {
4121 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4122 if(dest_conv) {
4123 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4129 if (dest_conv)
4131 ENTER_GL();
4133 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4134 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4135 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4136 dwCount * get_flexible_vertex_size(DestFVF),
4137 dest_conv_addr));
4138 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4140 LEAVE_GL();
4142 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4145 return WINED3D_OK;
4147 #undef copy_and_next
4149 /* Do not call while under the GL lock. */
4150 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4151 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4152 DWORD DestFVF)
4154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4155 struct wined3d_stream_info stream_info;
4156 const struct wined3d_gl_info *gl_info;
4157 struct wined3d_context *context;
4158 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4159 HRESULT hr;
4161 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4163 if(pVertexDecl) {
4164 ERR("Output vertex declaration not implemented yet\n");
4167 /* Need any context to write to the vbo. */
4168 context = context_acquire(This, NULL);
4169 gl_info = context->gl_info;
4171 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4172 * control the streamIsUP flag, thus restore it afterwards.
4174 This->stateBlock->state.user_stream = FALSE;
4175 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4176 This->stateBlock->state.user_stream = streamWasUP;
4178 if(vbo || SrcStartIndex) {
4179 unsigned int i;
4180 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4181 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4183 * Also get the start index in, but only loop over all elements if there's something to add at all.
4185 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4187 struct wined3d_stream_info_element *e;
4189 if (!(stream_info.use_map & (1 << i))) continue;
4191 e = &stream_info.elements[i];
4192 if (e->buffer_object)
4194 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4195 e->buffer_object = 0;
4196 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4197 ENTER_GL();
4198 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4199 vb->buffer_object = 0;
4200 LEAVE_GL();
4202 if (e->data) e->data += e->stride * SrcStartIndex;
4206 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4207 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4209 context_release(context);
4211 return hr;
4214 /*****
4215 * Get / Set Texture Stage States
4216 * TODO: Verify against dx9 definitions
4217 *****/
4218 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4221 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4222 DWORD oldValue;
4224 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4226 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4228 WARN("Invalid Type %d passed.\n", Type);
4229 return WINED3D_OK;
4232 if (Stage >= gl_info->limits.texture_stages)
4234 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4235 Stage, gl_info->limits.texture_stages - 1);
4236 return WINED3D_OK;
4239 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4240 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4241 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4243 if (This->isRecordingState) {
4244 TRACE("Recording... not performing anything\n");
4245 return WINED3D_OK;
4248 /* Checked after the assignments to allow proper stateblock recording */
4249 if(oldValue == Value) {
4250 TRACE("App is setting the old value over, nothing to do\n");
4251 return WINED3D_OK;
4254 if (Stage > This->stateBlock->state.lowest_disabled_stage
4255 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4256 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4258 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4259 * Changes in other states are important on disabled stages too
4261 return WINED3D_OK;
4264 if(Type == WINED3DTSS_COLOROP) {
4265 unsigned int i;
4267 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4268 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4269 * they have to be disabled
4271 * The current stage is dirtified below.
4273 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4275 TRACE("Additionally dirtifying stage %u\n", i);
4276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4278 This->stateBlock->state.lowest_disabled_stage = Stage;
4279 TRACE("New lowest disabled: %u\n", Stage);
4280 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4281 /* Previously disabled stage enabled. Stages above it may need enabling
4282 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4283 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4285 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4288 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4290 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4291 break;
4292 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4295 This->stateBlock->state.lowest_disabled_stage = i;
4296 TRACE("New lowest disabled: %u\n", i);
4300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4302 return WINED3D_OK;
4305 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4309 TRACE("iface %p, stage %u, state %s, value %p.\n",
4310 iface, Stage, debug_d3dtexturestate(Type), pValue);
4312 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4314 WARN("Invalid Type %d passed.\n", Type);
4315 return WINED3D_OK;
4318 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4319 TRACE("Returning %#x.\n", *pValue);
4321 return WINED3D_OK;
4324 /*****
4325 * Get / Set Texture
4326 *****/
4327 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4328 DWORD stage, IWineD3DBaseTexture *texture)
4330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4331 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4332 IWineD3DBaseTexture *prev;
4334 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4336 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4337 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4339 /* Windows accepts overflowing this array... we do not. */
4340 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4342 WARN("Ignoring invalid stage %u.\n", stage);
4343 return WINED3D_OK;
4346 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4347 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4349 WARN("Rejecting attempt to set scratch texture.\n");
4350 return WINED3DERR_INVALIDCALL;
4353 This->updateStateBlock->changed.textures |= 1 << stage;
4355 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4356 TRACE("Previous texture %p.\n", prev);
4358 if (texture == prev)
4360 TRACE("App is setting the same texture again, nothing to do.\n");
4361 return WINED3D_OK;
4364 TRACE("Setting new texture to %p.\n", texture);
4365 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4367 if (This->isRecordingState)
4369 TRACE("Recording... not performing anything\n");
4371 if (texture) IWineD3DBaseTexture_AddRef(texture);
4372 if (prev) IWineD3DBaseTexture_Release(prev);
4374 return WINED3D_OK;
4377 if (texture)
4379 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4380 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4381 GLenum dimensions = t->baseTexture.target;
4383 IWineD3DBaseTexture_AddRef(texture);
4385 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4386 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4388 if (!prev && stage < gl_info->limits.texture_stages)
4390 /* The source arguments for color and alpha ops have different
4391 * meanings when a NULL texture is bound, so the COLOROP and
4392 * ALPHAOP have to be dirtified. */
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4397 if (bind_count == 1) t->baseTexture.sampler = stage;
4400 if (prev)
4402 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4403 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4405 IWineD3DBaseTexture_Release(prev);
4407 if (!texture && stage < gl_info->limits.texture_stages)
4409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4413 if (bind_count && t->baseTexture.sampler == stage)
4415 unsigned int i;
4417 /* Search for other stages the texture is bound to. Shouldn't
4418 * happen if applications bind textures to a single stage only. */
4419 TRACE("Searching for other stages the texture is bound to.\n");
4420 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4422 if (This->updateStateBlock->state.textures[i] == t)
4424 TRACE("Texture is also bound to stage %u.\n", i);
4425 t->baseTexture.sampler = i;
4426 break;
4432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4434 return WINED3D_OK;
4437 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4442 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4443 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4446 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4448 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4449 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4452 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4453 if (*ppTexture)
4454 IWineD3DBaseTexture_AddRef(*ppTexture);
4456 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4458 return WINED3D_OK;
4461 /*****
4462 * Get Back Buffer
4463 *****/
4464 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4465 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4467 IWineD3DSwapChain *swapchain;
4468 HRESULT hr;
4470 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4471 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4473 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4474 if (FAILED(hr))
4476 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4477 return hr;
4480 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4481 IWineD3DSwapChain_Release(swapchain);
4482 if (FAILED(hr))
4484 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4485 return hr;
4488 return WINED3D_OK;
4491 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4493 WARN("(%p) : stub, calling idirect3d for now\n", This);
4494 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4497 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 IWineD3DSwapChain *swapChain;
4500 HRESULT hr;
4502 if(iSwapChain > 0) {
4503 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4504 if (hr == WINED3D_OK) {
4505 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4506 IWineD3DSwapChain_Release(swapChain);
4507 } else {
4508 FIXME("(%p) Error getting display mode\n", This);
4510 } else {
4511 /* Don't read the real display mode,
4512 but return the stored mode instead. X11 can't change the color
4513 depth, and some apps are pretty angry if they SetDisplayMode from
4514 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4516 Also don't relay to the swapchain because with ddraw it's possible
4517 that there isn't a swapchain at all */
4518 pMode->Width = This->ddraw_width;
4519 pMode->Height = This->ddraw_height;
4520 pMode->Format = This->ddraw_format;
4521 pMode->RefreshRate = 0;
4522 hr = WINED3D_OK;
4525 return hr;
4528 /*****
4529 * Stateblock related functions
4530 *****/
4532 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 IWineD3DStateBlock *stateblock;
4535 HRESULT hr;
4537 TRACE("(%p)\n", This);
4539 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4541 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4542 if (FAILED(hr)) return hr;
4544 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4545 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4546 This->isRecordingState = TRUE;
4548 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4550 return WINED3D_OK;
4553 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4555 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4557 if (!This->isRecordingState) {
4558 WARN("(%p) not recording! returning error\n", This);
4559 *ppStateBlock = NULL;
4560 return WINED3DERR_INVALIDCALL;
4563 stateblock_init_contained_states(object);
4565 *ppStateBlock = (IWineD3DStateBlock*) object;
4566 This->isRecordingState = FALSE;
4567 This->updateStateBlock = This->stateBlock;
4568 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4569 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4571 return WINED3D_OK;
4574 /*****
4575 * Scene related functions
4576 *****/
4577 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4578 /* At the moment we have no need for any functionality at the beginning
4579 of a scene */
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 TRACE("(%p)\n", This);
4583 if(This->inScene) {
4584 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4585 return WINED3DERR_INVALIDCALL;
4587 This->inScene = TRUE;
4588 return WINED3D_OK;
4591 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4594 struct wined3d_context *context;
4596 TRACE("(%p)\n", This);
4598 if(!This->inScene) {
4599 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4600 return WINED3DERR_INVALIDCALL;
4603 context = context_acquire(This, NULL);
4604 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4605 wglFlush();
4606 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4607 * fails. */
4608 context_release(context);
4610 This->inScene = FALSE;
4611 return WINED3D_OK;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4615 const RECT *pSourceRect, const RECT *pDestRect,
4616 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4618 IWineD3DSwapChain *swapChain = NULL;
4619 int i;
4620 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4622 TRACE("iface %p.\n", iface);
4624 for(i = 0 ; i < swapchains ; i ++) {
4626 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4627 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4628 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4629 IWineD3DSwapChain_Release(swapChain);
4632 return WINED3D_OK;
4635 /* Do not call while under the GL lock. */
4636 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4637 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4639 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4640 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4641 RECT draw_rect;
4643 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4644 iface, rect_count, rects, flags, color, depth, stencil);
4646 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4648 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4649 /* TODO: What about depth stencil buffers without stencil bits? */
4650 return WINED3DERR_INVALIDCALL;
4653 device_get_draw_rect(device, &draw_rect);
4655 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4656 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4659 /*****
4660 * Drawing functions
4661 *****/
4663 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4664 WINED3DPRIMITIVETYPE primitive_type)
4666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4670 This->updateStateBlock->changed.primitive_type = TRUE;
4671 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4674 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4675 WINED3DPRIMITIVETYPE *primitive_type)
4677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4679 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4681 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4683 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4686 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4690 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4692 if (!This->stateBlock->state.vertex_declaration)
4694 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4695 return WINED3DERR_INVALIDCALL;
4698 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4699 if (This->stateBlock->state.user_stream)
4701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4702 This->stateBlock->state.user_stream = FALSE;
4705 if (This->stateBlock->state.load_base_vertex_index)
4707 This->stateBlock->state.load_base_vertex_index = 0;
4708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4710 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4711 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4712 return WINED3D_OK;
4715 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 struct wined3d_buffer *index_buffer;
4719 UINT idxStride = 2;
4720 GLuint vbo;
4722 index_buffer = This->stateBlock->state.index_buffer;
4723 if (!index_buffer)
4725 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4726 * without an index buffer set. (The first time at least...)
4727 * D3D8 simply dies, but I doubt it can do much harm to return
4728 * D3DERR_INVALIDCALL there as well. */
4729 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4730 return WINED3DERR_INVALIDCALL;
4733 if (!This->stateBlock->state.vertex_declaration)
4735 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4736 return WINED3DERR_INVALIDCALL;
4739 if (This->stateBlock->state.user_stream)
4741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4742 This->stateBlock->state.user_stream = FALSE;
4744 vbo = index_buffer->buffer_object;
4746 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4748 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4749 idxStride = 2;
4750 else
4751 idxStride = 4;
4753 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4755 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4759 drawPrimitive(iface, index_count, startIndex, idxStride,
4760 vbo ? NULL : index_buffer->resource.allocatedMemory);
4762 return WINED3D_OK;
4765 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4766 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4769 struct wined3d_stream_state *stream;
4770 IWineD3DBuffer *vb;
4772 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4773 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4775 if (!This->stateBlock->state.vertex_declaration)
4777 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4778 return WINED3DERR_INVALIDCALL;
4781 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4782 stream = &This->stateBlock->state.streams[0];
4783 vb = (IWineD3DBuffer *)stream->buffer;
4784 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4785 if (vb) IWineD3DBuffer_Release(vb);
4786 stream->offset = 0;
4787 stream->stride = VertexStreamZeroStride;
4788 This->stateBlock->state.user_stream = TRUE;
4789 This->stateBlock->state.load_base_vertex_index = 0;
4791 /* TODO: Only mark dirty if drawing from a different UP address */
4792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4794 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4796 /* MSDN specifies stream zero settings must be set to NULL */
4797 stream->buffer = NULL;
4798 stream->stride = 0;
4800 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4801 * the new stream sources or use UP drawing again
4803 return WINED3D_OK;
4806 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4807 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4808 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4810 int idxStride;
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 struct wined3d_stream_state *stream;
4813 IWineD3DBuffer *vb;
4814 IWineD3DBuffer *ib;
4816 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4817 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4819 if (!This->stateBlock->state.vertex_declaration)
4821 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4822 return WINED3DERR_INVALIDCALL;
4825 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4826 idxStride = 2;
4827 } else {
4828 idxStride = 4;
4831 stream = &This->stateBlock->state.streams[0];
4832 vb = (IWineD3DBuffer *)stream->buffer;
4833 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4834 if (vb) IWineD3DBuffer_Release(vb);
4835 stream->offset = 0;
4836 stream->stride = VertexStreamZeroStride;
4837 This->stateBlock->state.user_stream = TRUE;
4839 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4840 This->stateBlock->state.base_vertex_index = 0;
4841 This->stateBlock->state.load_base_vertex_index = 0;
4842 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4846 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4848 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4849 stream->buffer = NULL;
4850 stream->stride = 0;
4851 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4852 if (ib)
4854 IWineD3DBuffer_Release(ib);
4855 This->stateBlock->state.index_buffer = NULL;
4857 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4858 * SetStreamSource to specify a vertex buffer
4861 return WINED3D_OK;
4864 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4865 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4869 /* Mark the state dirty until we have nicer tracking
4870 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4871 * that value.
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4875 This->stateBlock->state.base_vertex_index = 0;
4876 This->up_strided = DrawPrimStrideData;
4877 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4878 This->up_strided = NULL;
4879 return WINED3D_OK;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4883 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4884 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4887 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4889 /* Mark the state dirty until we have nicer tracking
4890 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4891 * that value.
4893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4894 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4895 This->stateBlock->state.user_stream = TRUE;
4896 This->stateBlock->state.base_vertex_index = 0;
4897 This->up_strided = DrawPrimStrideData;
4898 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4899 This->up_strided = NULL;
4900 return WINED3D_OK;
4903 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4904 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4905 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4907 WINED3DLOCKED_BOX src;
4908 WINED3DLOCKED_BOX dst;
4909 HRESULT hr;
4911 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4912 iface, pSourceVolume, pDestinationVolume);
4914 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4915 * dirtification to improve loading performance.
4917 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4918 if(FAILED(hr)) return hr;
4919 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4920 if(FAILED(hr)) {
4921 IWineD3DVolume_UnlockBox(pSourceVolume);
4922 return hr;
4925 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4927 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4928 if(FAILED(hr)) {
4929 IWineD3DVolume_UnlockBox(pSourceVolume);
4930 } else {
4931 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4933 return hr;
4936 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4937 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4939 unsigned int level_count, i;
4940 WINED3DRESOURCETYPE type;
4941 HRESULT hr;
4943 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4945 /* Verify that the source and destination textures are non-NULL. */
4946 if (!src_texture || !dst_texture)
4948 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4949 return WINED3DERR_INVALIDCALL;
4952 if (src_texture == dst_texture)
4954 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4955 return WINED3DERR_INVALIDCALL;
4958 /* Verify that the source and destination textures are the same type. */
4959 type = IWineD3DBaseTexture_GetType(src_texture);
4960 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4962 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4963 return WINED3DERR_INVALIDCALL;
4966 /* Check that both textures have the identical numbers of levels. */
4967 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4968 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4970 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4971 return WINED3DERR_INVALIDCALL;
4974 /* Make sure that the destination texture is loaded. */
4975 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4977 /* Update every surface level of the texture. */
4978 switch (type)
4980 case WINED3DRTYPE_TEXTURE:
4982 IWineD3DSurface *src_surface;
4983 IWineD3DSurface *dst_surface;
4985 for (i = 0; i < level_count; ++i)
4987 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4988 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4989 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4990 IWineD3DSurface_Release(dst_surface);
4991 IWineD3DSurface_Release(src_surface);
4992 if (FAILED(hr))
4994 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4995 return hr;
4998 break;
5001 case WINED3DRTYPE_CUBETEXTURE:
5003 IWineD3DSurface *src_surface;
5004 IWineD3DSurface *dst_surface;
5005 WINED3DCUBEMAP_FACES face;
5007 for (i = 0; i < level_count; ++i)
5009 /* Update each cube face. */
5010 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5012 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5013 face, i, &src_surface);
5014 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5015 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5016 face, i, &dst_surface);
5017 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5018 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5019 IWineD3DSurface_Release(dst_surface);
5020 IWineD3DSurface_Release(src_surface);
5021 if (FAILED(hr))
5023 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5024 return hr;
5028 break;
5031 case WINED3DRTYPE_VOLUMETEXTURE:
5033 IWineD3DVolume *src_volume;
5034 IWineD3DVolume *dst_volume;
5036 for (i = 0; i < level_count; ++i)
5038 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5039 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5040 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5041 IWineD3DVolume_Release(dst_volume);
5042 IWineD3DVolume_Release(src_volume);
5043 if (FAILED(hr))
5045 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5046 return hr;
5049 break;
5052 default:
5053 FIXME("Unsupported texture type %#x.\n", type);
5054 return WINED3DERR_INVALIDCALL;
5057 return WINED3D_OK;
5060 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5061 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5063 IWineD3DSwapChain *swapchain;
5064 HRESULT hr;
5066 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5068 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5069 if (FAILED(hr)) return hr;
5071 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5072 IWineD3DSwapChain_Release(swapchain);
5074 return hr;
5077 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5079 IWineD3DBaseTextureImpl *texture;
5080 DWORD i;
5082 TRACE("(%p) : %p\n", This, pNumPasses);
5084 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5086 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5088 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5089 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5091 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5093 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5094 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5097 texture = This->stateBlock->state.textures[i];
5098 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5100 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5102 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5103 return E_FAIL;
5105 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5107 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5108 return E_FAIL;
5110 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5111 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5113 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5114 return E_FAIL;
5118 /* return a sensible default */
5119 *pNumPasses = 1;
5121 TRACE("returning D3D_OK\n");
5122 return WINED3D_OK;
5125 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5127 int i;
5129 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5131 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5132 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5133 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5135 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5140 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 int j;
5143 UINT NewSize;
5144 PALETTEENTRY **palettes;
5146 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5148 if (PaletteNumber >= MAX_PALETTES) {
5149 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5150 return WINED3DERR_INVALIDCALL;
5153 if (PaletteNumber >= This->NumberOfPalettes) {
5154 NewSize = This->NumberOfPalettes;
5155 do {
5156 NewSize *= 2;
5157 } while(PaletteNumber >= NewSize);
5158 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5159 if (!palettes) {
5160 ERR("Out of memory!\n");
5161 return E_OUTOFMEMORY;
5163 This->palettes = palettes;
5164 This->NumberOfPalettes = NewSize;
5167 if (!This->palettes[PaletteNumber]) {
5168 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5169 if (!This->palettes[PaletteNumber]) {
5170 ERR("Out of memory!\n");
5171 return E_OUTOFMEMORY;
5175 for (j = 0; j < 256; ++j) {
5176 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5177 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5178 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5179 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5181 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5182 TRACE("(%p) : returning\n", This);
5183 return WINED3D_OK;
5186 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5188 int j;
5189 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5190 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5191 /* What happens in such situation isn't documented; Native seems to silently abort
5192 on such conditions. Return Invalid Call. */
5193 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5194 return WINED3DERR_INVALIDCALL;
5196 for (j = 0; j < 256; ++j) {
5197 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5198 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5199 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5200 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5202 TRACE("(%p) : returning\n", This);
5203 return WINED3D_OK;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5209 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5210 (tested with reference rasterizer). Return Invalid Call. */
5211 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5212 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5213 return WINED3DERR_INVALIDCALL;
5215 /*TODO: stateblocks */
5216 if (This->currentPalette != PaletteNumber) {
5217 This->currentPalette = PaletteNumber;
5218 dirtify_p8_texture_samplers(This);
5220 TRACE("(%p) : returning\n", This);
5221 return WINED3D_OK;
5224 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5227 if (!PaletteNumber)
5229 WARN("(%p) : returning Invalid Call\n", This);
5230 return WINED3DERR_INVALIDCALL;
5232 /*TODO: stateblocks */
5233 *PaletteNumber = This->currentPalette;
5234 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5235 return WINED3D_OK;
5238 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240 static BOOL warned;
5241 if (!warned)
5243 FIXME("(%p) : stub\n", This);
5244 warned = TRUE;
5247 This->softwareVertexProcessing = bSoftware;
5248 return WINED3D_OK;
5252 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5254 static BOOL warned;
5255 if (!warned)
5257 FIXME("(%p) : stub\n", This);
5258 warned = TRUE;
5260 return This->softwareVertexProcessing;
5263 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5264 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5266 IWineD3DSwapChain *swapchain;
5267 HRESULT hr;
5269 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5270 iface, swapchain_idx, raster_status);
5272 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5273 if (FAILED(hr))
5275 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5276 return hr;
5279 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5280 IWineD3DSwapChain_Release(swapchain);
5281 if (FAILED(hr))
5283 WARN("Failed to get raster status, hr %#x.\n", hr);
5284 return hr;
5287 return WINED3D_OK;
5290 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5292 static BOOL warned;
5293 if(nSegments != 0.0f) {
5294 if (!warned)
5296 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5297 warned = TRUE;
5300 return WINED3D_OK;
5303 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5305 static BOOL warned;
5306 if (!warned)
5308 FIXME("iface %p stub!\n", iface);
5309 warned = TRUE;
5311 return 0.0f;
5314 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5315 IWineD3DSurface *src_surface, const RECT *src_rect,
5316 IWineD3DSurface *dst_surface, const POINT *dst_point)
5318 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5319 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5321 const struct wined3d_format *src_format;
5322 const struct wined3d_format *dst_format;
5323 const struct wined3d_gl_info *gl_info;
5324 struct wined3d_context *context;
5325 const unsigned char *data;
5326 UINT update_w, update_h;
5327 CONVERT_TYPES convert;
5328 UINT src_w, src_h;
5329 UINT dst_x, dst_y;
5330 DWORD sampler;
5331 struct wined3d_format format;
5333 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5334 iface, src_surface, wine_dbgstr_rect(src_rect),
5335 dst_surface, wine_dbgstr_point(dst_point));
5337 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5339 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5340 src_surface, dst_surface);
5341 return WINED3DERR_INVALIDCALL;
5344 src_format = src_impl->resource.format;
5345 dst_format = dst_impl->resource.format;
5347 if (src_format->id != dst_format->id)
5349 WARN("Source and destination surfaces should have the same format.\n");
5350 return WINED3DERR_INVALIDCALL;
5353 dst_x = dst_point ? dst_point->x : 0;
5354 dst_y = dst_point ? dst_point->y : 0;
5356 /* This call loads the OpenGL surface directly, instead of copying the
5357 * surface to the destination's sysmem copy. If surface conversion is
5358 * needed, use BltFast instead to copy in sysmem and use regular surface
5359 * loading. */
5360 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5361 if (convert != NO_CONVERSION || format.convert)
5362 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5364 context = context_acquire(This, NULL);
5365 gl_info = context->gl_info;
5367 ENTER_GL();
5368 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5369 checkGLcall("glActiveTextureARB");
5370 LEAVE_GL();
5372 /* Make sure the surface is loaded and up to date */
5373 surface_internal_preload(dst_impl, SRGB_RGB);
5374 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5376 src_w = src_impl->currentDesc.Width;
5377 src_h = src_impl->currentDesc.Height;
5378 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5379 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5381 data = IWineD3DSurface_GetData(src_surface);
5382 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5384 ENTER_GL();
5386 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5388 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5389 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5390 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5392 if (src_rect)
5394 data += (src_rect->top / src_format->block_height) * src_pitch;
5395 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5398 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5399 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5400 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5402 if (row_length == src_pitch)
5404 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5405 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5407 else
5409 UINT row, y;
5411 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5412 * can't use the unpack row length like below. */
5413 for (row = 0, y = dst_y; row < row_count; ++row)
5415 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5416 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5417 y += src_format->block_height;
5418 data += src_pitch;
5421 checkGLcall("glCompressedTexSubImage2DARB");
5423 else
5425 if (src_rect)
5427 data += src_rect->top * src_w * src_format->byte_count;
5428 data += src_rect->left * src_format->byte_count;
5431 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5432 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5433 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5435 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5436 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5437 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5438 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5439 checkGLcall("glTexSubImage2D");
5442 LEAVE_GL();
5443 context_release(context);
5445 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5446 sampler = This->rev_tex_unit_map[0];
5447 if (sampler != WINED3D_UNMAPPED_STAGE)
5449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5452 return WINED3D_OK;
5455 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5457 struct WineD3DRectPatch *patch;
5458 GLenum old_primitive_type;
5459 unsigned int i;
5460 struct list *e;
5461 BOOL found;
5462 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5464 if(!(Handle || pRectPatchInfo)) {
5465 /* TODO: Write a test for the return value, thus the FIXME */
5466 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5467 return WINED3DERR_INVALIDCALL;
5470 if(Handle) {
5471 i = PATCHMAP_HASHFUNC(Handle);
5472 found = FALSE;
5473 LIST_FOR_EACH(e, &This->patches[i]) {
5474 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5475 if(patch->Handle == Handle) {
5476 found = TRUE;
5477 break;
5481 if(!found) {
5482 TRACE("Patch does not exist. Creating a new one\n");
5483 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5484 patch->Handle = Handle;
5485 list_add_head(&This->patches[i], &patch->entry);
5486 } else {
5487 TRACE("Found existing patch %p\n", patch);
5489 } else {
5490 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5491 * attributes we have to tesselate, read back, and draw. This needs a patch
5492 * management structure instance. Create one.
5494 * A possible improvement is to check if a vertex shader is used, and if not directly
5495 * draw the patch.
5497 FIXME("Drawing an uncached patch. This is slow\n");
5498 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5501 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5502 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5503 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5505 HRESULT hr;
5506 TRACE("Tesselation density or patch info changed, retesselating\n");
5508 if(pRectPatchInfo) {
5509 patch->RectPatchInfo = *pRectPatchInfo;
5511 patch->numSegs[0] = pNumSegs[0];
5512 patch->numSegs[1] = pNumSegs[1];
5513 patch->numSegs[2] = pNumSegs[2];
5514 patch->numSegs[3] = pNumSegs[3];
5516 hr = tesselate_rectpatch(This, patch);
5517 if(FAILED(hr)) {
5518 WARN("Patch tesselation failed\n");
5520 /* Do not release the handle to store the params of the patch */
5521 if(!Handle) {
5522 HeapFree(GetProcessHeap(), 0, patch);
5524 return hr;
5528 This->currentPatch = patch;
5529 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5530 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5531 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5532 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5533 This->currentPatch = NULL;
5535 /* Destroy uncached patches */
5536 if(!Handle) {
5537 HeapFree(GetProcessHeap(), 0, patch->mem);
5538 HeapFree(GetProcessHeap(), 0, patch);
5540 return WINED3D_OK;
5543 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5544 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5546 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5547 iface, handle, segment_count, patch_info);
5549 return WINED3D_OK;
5552 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 int i;
5555 struct WineD3DRectPatch *patch;
5556 struct list *e;
5557 TRACE("(%p) Handle(%d)\n", This, Handle);
5559 i = PATCHMAP_HASHFUNC(Handle);
5560 LIST_FOR_EACH(e, &This->patches[i]) {
5561 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5562 if(patch->Handle == Handle) {
5563 TRACE("Deleting patch %p\n", patch);
5564 list_remove(&patch->entry);
5565 HeapFree(GetProcessHeap(), 0, patch->mem);
5566 HeapFree(GetProcessHeap(), 0, patch);
5567 return WINED3D_OK;
5571 /* TODO: Write a test for the return value */
5572 FIXME("Attempt to destroy nonexistent patch\n");
5573 return WINED3DERR_INVALIDCALL;
5576 /* Do not call while under the GL lock. */
5577 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5578 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5580 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5582 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5583 iface, surface, wine_dbgstr_rect(rect),
5584 color->r, color->g, color->b, color->a);
5586 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5588 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5589 return WINED3DERR_INVALIDCALL;
5592 return surface_color_fill(s, rect, color);
5595 /* Do not call while under the GL lock. */
5596 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5597 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5599 IWineD3DResource *resource;
5600 HRESULT hr;
5602 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5603 if (FAILED(hr))
5605 ERR("Failed to get resource, hr %#x\n", hr);
5606 return;
5609 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5611 FIXME("Only supported on surface resources\n");
5612 IWineD3DResource_Release(resource);
5613 return;
5616 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5617 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5619 IWineD3DResource_Release(resource);
5622 /* rendertarget and depth stencil functions */
5623 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5624 DWORD render_target_idx, IWineD3DSurface **render_target)
5626 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5628 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5629 iface, render_target_idx, render_target);
5631 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5633 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5634 return WINED3DERR_INVALIDCALL;
5637 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5638 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5640 TRACE("Returning render target %p.\n", *render_target);
5642 return WINED3D_OK;
5645 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5647 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5649 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5651 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5652 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5653 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5654 IWineD3DSurface_AddRef(*depth_stencil);
5656 return WINED3D_OK;
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5660 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5662 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5663 IWineD3DSurfaceImpl *prev;
5665 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5666 iface, render_target_idx, render_target, set_viewport);
5668 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5670 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5671 return WINED3DERR_INVALIDCALL;
5674 prev = device->render_targets[render_target_idx];
5675 if (render_target == (IWineD3DSurface *)prev)
5677 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5678 return WINED3D_OK;
5681 /* Render target 0 can't be set to NULL. */
5682 if (!render_target && !render_target_idx)
5684 WARN("Trying to set render target 0 to NULL.\n");
5685 return WINED3DERR_INVALIDCALL;
5688 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5690 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5691 return WINED3DERR_INVALIDCALL;
5694 if (render_target) IWineD3DSurface_AddRef(render_target);
5695 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5696 /* Release after the assignment, to prevent device_resource_released()
5697 * from seeing the surface as still in use. */
5698 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5700 /* Render target 0 is special. */
5701 if (!render_target_idx && set_viewport)
5703 /* Set the viewport and scissor rectangles, if requested. Tests show
5704 * that stateblock recording is ignored, the change goes directly
5705 * into the primary stateblock. */
5706 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5707 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5708 device->stateBlock->state.viewport.X = 0;
5709 device->stateBlock->state.viewport.Y = 0;
5710 device->stateBlock->state.viewport.MaxZ = 1.0f;
5711 device->stateBlock->state.viewport.MinZ = 0.0f;
5712 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5714 device->stateBlock->state.scissor_rect.top = 0;
5715 device->stateBlock->state.scissor_rect.left = 0;
5716 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5717 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5718 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5721 return WINED3D_OK;
5724 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5727 IWineD3DSurfaceImpl *tmp;
5729 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5731 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5733 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5734 return WINED3D_OK;
5737 if (This->depth_stencil)
5739 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5740 || This->depth_stencil->Flags & SFLAG_DISCARD)
5742 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5743 This->depth_stencil->currentDesc.Width,
5744 This->depth_stencil->currentDesc.Height);
5745 if (This->depth_stencil == This->onscreen_depth_stencil)
5747 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5748 This->onscreen_depth_stencil = NULL;
5753 tmp = This->depth_stencil;
5754 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5755 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5756 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5758 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5760 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5766 return WINED3D_OK;
5769 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5770 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5773 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5774 WINED3DLOCKED_RECT lockedRect;
5776 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5777 iface, XHotSpot, YHotSpot, cursor_image);
5779 /* some basic validation checks */
5780 if (This->cursorTexture)
5782 struct wined3d_context *context = context_acquire(This, NULL);
5783 ENTER_GL();
5784 glDeleteTextures(1, &This->cursorTexture);
5785 LEAVE_GL();
5786 context_release(context);
5787 This->cursorTexture = 0;
5790 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5791 This->haveHardwareCursor = TRUE;
5792 else
5793 This->haveHardwareCursor = FALSE;
5795 if (cursor_image)
5797 WINED3DLOCKED_RECT rect;
5799 /* MSDN: Cursor must be A8R8G8B8 */
5800 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5802 WARN("surface %p has an invalid format.\n", cursor_image);
5803 return WINED3DERR_INVALIDCALL;
5806 /* MSDN: Cursor must be smaller than the display mode */
5807 if (s->currentDesc.Width > This->ddraw_width
5808 || s->currentDesc.Height > This->ddraw_height)
5810 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5811 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5812 return WINED3DERR_INVALIDCALL;
5815 if (!This->haveHardwareCursor) {
5816 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5818 /* Do not store the surface's pointer because the application may
5819 * release it after setting the cursor image. Windows doesn't
5820 * addref the set surface, so we can't do this either without
5821 * creating circular refcount dependencies. Copy out the gl texture
5822 * instead.
5824 This->cursorWidth = s->currentDesc.Width;
5825 This->cursorHeight = s->currentDesc.Height;
5826 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5828 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5829 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5830 struct wined3d_context *context;
5831 char *mem, *bits = rect.pBits;
5832 GLint intfmt = format->glInternal;
5833 GLint gl_format = format->glFormat;
5834 GLint type = format->glType;
5835 INT height = This->cursorHeight;
5836 INT width = This->cursorWidth;
5837 INT bpp = format->byte_count;
5838 DWORD sampler;
5839 INT i;
5841 /* Reformat the texture memory (pitch and width can be
5842 * different) */
5843 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5844 for(i = 0; i < height; i++)
5845 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5846 IWineD3DSurface_UnlockRect(cursor_image);
5848 context = context_acquire(This, NULL);
5850 ENTER_GL();
5852 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5854 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5855 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5858 /* Make sure that a proper texture unit is selected */
5859 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5860 checkGLcall("glActiveTextureARB");
5861 sampler = This->rev_tex_unit_map[0];
5862 if (sampler != WINED3D_UNMAPPED_STAGE)
5864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5866 /* Create a new cursor texture */
5867 glGenTextures(1, &This->cursorTexture);
5868 checkGLcall("glGenTextures");
5869 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5870 checkGLcall("glBindTexture");
5871 /* Copy the bitmap memory into the cursor texture */
5872 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5873 HeapFree(GetProcessHeap(), 0, mem);
5874 checkGLcall("glTexImage2D");
5876 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5878 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5879 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5882 LEAVE_GL();
5884 context_release(context);
5886 else
5888 FIXME("A cursor texture was not returned.\n");
5889 This->cursorTexture = 0;
5892 else
5894 /* Draw a hardware cursor */
5895 ICONINFO cursorInfo;
5896 HCURSOR cursor;
5897 /* Create and clear maskBits because it is not needed for
5898 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5899 * chunks. */
5900 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5901 (s->currentDesc.Width * s->currentDesc.Height / 8));
5902 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5903 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5904 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5906 cursorInfo.fIcon = FALSE;
5907 cursorInfo.xHotspot = XHotSpot;
5908 cursorInfo.yHotspot = YHotSpot;
5909 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5910 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5911 IWineD3DSurface_UnlockRect(cursor_image);
5912 /* Create our cursor and clean up. */
5913 cursor = CreateIconIndirect(&cursorInfo);
5914 SetCursor(cursor);
5915 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5916 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5917 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5918 This->hardwareCursor = cursor;
5919 HeapFree(GetProcessHeap(), 0, maskBits);
5923 This->xHotSpot = XHotSpot;
5924 This->yHotSpot = YHotSpot;
5925 return WINED3D_OK;
5928 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5930 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5932 This->xScreenSpace = XScreenSpace;
5933 This->yScreenSpace = YScreenSpace;
5935 return;
5939 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5941 BOOL oldVisible = This->bCursorVisible;
5942 POINT pt;
5944 TRACE("(%p) : visible(%d)\n", This, bShow);
5947 * When ShowCursor is first called it should make the cursor appear at the OS's last
5948 * known cursor position. Because of this, some applications just repetitively call
5949 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5951 GetCursorPos(&pt);
5952 This->xScreenSpace = pt.x;
5953 This->yScreenSpace = pt.y;
5955 if (This->haveHardwareCursor) {
5956 This->bCursorVisible = bShow;
5957 if (bShow)
5958 SetCursor(This->hardwareCursor);
5959 else
5960 SetCursor(NULL);
5962 else
5964 if (This->cursorTexture)
5965 This->bCursorVisible = bShow;
5968 return oldVisible;
5971 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
5972 TRACE("checking resource %p for eviction\n", resource);
5973 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
5974 TRACE("Evicting %p\n", resource);
5975 IWineD3DResource_UnLoad(resource);
5977 IWineD3DResource_Release(resource);
5978 return S_OK;
5981 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
5983 TRACE("iface %p.\n", iface);
5985 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
5986 /* Invalidate stream sources, the buffer(s) may have been evicted. */
5987 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
5989 return WINED3D_OK;
5992 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
5994 IWineD3DDeviceImpl *device = surface->resource.device;
5995 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5997 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5998 if(surface->Flags & SFLAG_DIBSECTION) {
5999 /* Release the DC */
6000 SelectObject(surface->hDC, surface->dib.holdbitmap);
6001 DeleteDC(surface->hDC);
6002 /* Release the DIB section */
6003 DeleteObject(surface->dib.DIBsection);
6004 surface->dib.bitmap_data = NULL;
6005 surface->resource.allocatedMemory = NULL;
6006 surface->Flags &= ~SFLAG_DIBSECTION;
6008 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6009 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6010 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6011 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6013 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6014 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6015 } else {
6016 surface->pow2Width = surface->pow2Height = 1;
6017 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6018 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6021 if (surface->texture_name)
6023 struct wined3d_context *context = context_acquire(device, NULL);
6024 ENTER_GL();
6025 glDeleteTextures(1, &surface->texture_name);
6026 LEAVE_GL();
6027 context_release(context);
6028 surface->texture_name = 0;
6029 surface->Flags &= ~SFLAG_CLIENT;
6031 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6032 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6033 surface->Flags |= SFLAG_NONPOW2;
6034 } else {
6035 surface->Flags &= ~SFLAG_NONPOW2;
6037 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6038 surface->resource.allocatedMemory = NULL;
6039 surface->resource.heapMemory = NULL;
6040 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6042 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6043 * to a FBO */
6044 if (!surface_init_sysmem(surface))
6046 return E_OUTOFMEMORY;
6048 return WINED3D_OK;
6051 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6052 TRACE("Unloading resource %p\n", resource);
6053 IWineD3DResource_UnLoad(resource);
6054 IWineD3DResource_Release(resource);
6055 return S_OK;
6058 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6060 UINT i, count;
6061 WINED3DDISPLAYMODE m;
6062 HRESULT hr;
6064 /* All Windowed modes are supported, as is leaving the current mode */
6065 if(pp->Windowed) return TRUE;
6066 if(!pp->BackBufferWidth) return TRUE;
6067 if(!pp->BackBufferHeight) return TRUE;
6069 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6070 for(i = 0; i < count; i++) {
6071 memset(&m, 0, sizeof(m));
6072 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6073 if(FAILED(hr)) {
6074 ERR("EnumAdapterModes failed\n");
6076 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6077 /* Mode found, it is supported */
6078 return TRUE;
6081 /* Mode not found -> not supported */
6082 return FALSE;
6085 /* Do not call while under the GL lock. */
6086 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6089 const struct wined3d_gl_info *gl_info;
6090 struct wined3d_context *context;
6091 IWineD3DBaseShaderImpl *shader;
6093 context = context_acquire(This, NULL);
6094 gl_info = context->gl_info;
6096 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6097 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6098 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6101 ENTER_GL();
6102 if(This->depth_blt_texture) {
6103 glDeleteTextures(1, &This->depth_blt_texture);
6104 This->depth_blt_texture = 0;
6106 if (This->depth_blt_rb) {
6107 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6108 This->depth_blt_rb = 0;
6109 This->depth_blt_rb_w = 0;
6110 This->depth_blt_rb_h = 0;
6112 LEAVE_GL();
6114 This->blitter->free_private(iface);
6115 This->frag_pipe->free_private(iface);
6116 This->shader_backend->shader_free_private(iface);
6117 destroy_dummy_textures(This, gl_info);
6119 context_release(context);
6121 while (This->numContexts)
6123 context_destroy(This, This->contexts[0]);
6125 HeapFree(GetProcessHeap(), 0, swapchain->context);
6126 swapchain->context = NULL;
6127 swapchain->num_contexts = 0;
6130 /* Do not call while under the GL lock. */
6131 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6134 struct wined3d_context *context;
6135 HRESULT hr;
6136 IWineD3DSurfaceImpl *target;
6138 /* Recreate the primary swapchain's context */
6139 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6140 if (!swapchain->context)
6142 ERR("Failed to allocate memory for swapchain context array.\n");
6143 return E_OUTOFMEMORY;
6146 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6147 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6149 WARN("Failed to create context.\n");
6150 HeapFree(GetProcessHeap(), 0, swapchain->context);
6151 return E_FAIL;
6154 swapchain->context[0] = context;
6155 swapchain->num_contexts = 1;
6156 create_dummy_textures(This);
6157 context_release(context);
6159 hr = This->shader_backend->shader_alloc_private(iface);
6160 if (FAILED(hr))
6162 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6163 goto err;
6166 hr = This->frag_pipe->alloc_private(iface);
6167 if (FAILED(hr))
6169 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6170 This->shader_backend->shader_free_private(iface);
6171 goto err;
6174 hr = This->blitter->alloc_private(iface);
6175 if (FAILED(hr))
6177 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6178 This->frag_pipe->free_private(iface);
6179 This->shader_backend->shader_free_private(iface);
6180 goto err;
6183 return WINED3D_OK;
6185 err:
6186 context_acquire(This, NULL);
6187 destroy_dummy_textures(This, context->gl_info);
6188 context_release(context);
6189 context_destroy(This, context);
6190 HeapFree(GetProcessHeap(), 0, swapchain->context);
6191 swapchain->num_contexts = 0;
6192 return hr;
6195 /* Do not call while under the GL lock. */
6196 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6197 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6200 IWineD3DSwapChainImpl *swapchain;
6201 HRESULT hr;
6202 BOOL DisplayModeChanged = FALSE;
6203 WINED3DDISPLAYMODE mode;
6204 TRACE("(%p)\n", This);
6206 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6207 if(FAILED(hr)) {
6208 ERR("Failed to get the first implicit swapchain\n");
6209 return hr;
6212 if(!is_display_mode_supported(This, pPresentationParameters)) {
6213 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6214 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6215 pPresentationParameters->BackBufferHeight);
6216 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6217 return WINED3DERR_INVALIDCALL;
6220 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6221 * on an existing gl context, so there's no real need for recreation.
6223 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6225 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6227 TRACE("New params:\n");
6228 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6229 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6230 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6231 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6232 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6233 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6234 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6235 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6236 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6237 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6238 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6239 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6240 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6242 /* No special treatment of these parameters. Just store them */
6243 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6244 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6245 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6246 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6248 /* What to do about these? */
6249 if (pPresentationParameters->BackBufferCount
6250 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6251 ERR("Cannot change the back buffer count yet\n");
6253 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6254 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6255 ERR("Cannot change the back buffer format yet\n");
6258 if (pPresentationParameters->hDeviceWindow
6259 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6260 ERR("Cannot change the device window yet\n");
6262 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6264 HRESULT hrc;
6266 TRACE("Creating the depth stencil buffer\n");
6268 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6269 pPresentationParameters->BackBufferWidth,
6270 pPresentationParameters->BackBufferHeight,
6271 pPresentationParameters->AutoDepthStencilFormat,
6272 pPresentationParameters->MultiSampleType,
6273 pPresentationParameters->MultiSampleQuality,
6274 FALSE,
6275 (IWineD3DSurface **)&This->auto_depth_stencil);
6277 if (FAILED(hrc)) {
6278 ERR("Failed to create the depth stencil buffer\n");
6279 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6280 return WINED3DERR_INVALIDCALL;
6284 if (This->onscreen_depth_stencil)
6286 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6287 This->onscreen_depth_stencil = NULL;
6290 /* Reset the depth stencil */
6291 if (pPresentationParameters->EnableAutoDepthStencil)
6292 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6293 else
6294 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6296 TRACE("Resetting stateblock\n");
6297 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6298 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6300 delete_opengl_contexts(iface, swapchain);
6302 if(pPresentationParameters->Windowed) {
6303 mode.Width = swapchain->orig_width;
6304 mode.Height = swapchain->orig_height;
6305 mode.RefreshRate = 0;
6306 mode.Format = swapchain->presentParms.BackBufferFormat;
6307 } else {
6308 mode.Width = pPresentationParameters->BackBufferWidth;
6309 mode.Height = pPresentationParameters->BackBufferHeight;
6310 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6311 mode.Format = swapchain->presentParms.BackBufferFormat;
6314 /* Should Width == 800 && Height == 0 set 800x600? */
6315 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6316 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6317 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6319 UINT i;
6321 if(!pPresentationParameters->Windowed) {
6322 DisplayModeChanged = TRUE;
6324 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6325 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6327 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6328 if(FAILED(hr))
6330 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6331 return hr;
6334 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6336 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6337 if(FAILED(hr))
6339 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6340 return hr;
6343 if (This->auto_depth_stencil)
6345 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6346 if(FAILED(hr))
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6349 return hr;
6354 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6355 || DisplayModeChanged)
6357 BOOL filter = This->filter_messages;
6358 This->filter_messages = TRUE;
6360 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6362 if (!pPresentationParameters->Windowed)
6364 if (swapchain->presentParms.Windowed)
6366 HWND focus_window = This->createParms.hFocusWindow;
6367 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6368 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6370 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6371 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6372 return hr;
6375 /* switch from windowed to fs */
6376 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6377 pPresentationParameters->BackBufferHeight);
6379 else
6381 /* Fullscreen -> fullscreen mode change */
6382 MoveWindow(swapchain->device_window, 0, 0,
6383 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6384 TRUE);
6387 else if (!swapchain->presentParms.Windowed)
6389 /* Fullscreen -> windowed switch */
6390 swapchain_restore_fullscreen_window(swapchain);
6391 IWineD3DDevice_ReleaseFocusWindow(iface);
6393 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6395 This->filter_messages = filter;
6397 else if (!pPresentationParameters->Windowed)
6399 DWORD style = This->style, exStyle = This->exStyle;
6400 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6401 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6402 * Reset to clear up their mess. Guild Wars also loses the device during that.
6404 This->style = 0;
6405 This->exStyle = 0;
6406 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6407 pPresentationParameters->BackBufferHeight);
6408 This->style = style;
6409 This->exStyle = exStyle;
6412 /* Note: No parent needed for initial internal stateblock */
6413 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6414 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6415 else TRACE("Created stateblock %p\n", This->stateBlock);
6416 This->updateStateBlock = This->stateBlock;
6417 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6419 stateblock_init_default_state(This->stateBlock);
6421 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6423 RECT client_rect;
6424 GetClientRect(swapchain->win_handle, &client_rect);
6426 if(!swapchain->presentParms.BackBufferCount)
6428 TRACE("Single buffered rendering\n");
6429 swapchain->render_to_fbo = FALSE;
6431 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6432 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6434 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6435 swapchain->presentParms.BackBufferWidth,
6436 swapchain->presentParms.BackBufferHeight,
6437 client_rect.right, client_rect.bottom);
6438 swapchain->render_to_fbo = TRUE;
6440 else
6442 TRACE("Rendering directly to GL_BACK\n");
6443 swapchain->render_to_fbo = FALSE;
6447 hr = create_primary_opengl_context(iface, swapchain);
6448 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6450 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6451 * first use
6453 return hr;
6456 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6458 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6460 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6462 return WINED3D_OK;
6466 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6468 TRACE("(%p) : pParameters %p\n", This, pParameters);
6470 *pParameters = This->createParms;
6471 return WINED3D_OK;
6474 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6475 IWineD3DSwapChain *swapchain;
6477 TRACE("Relaying to swapchain\n");
6479 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6480 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6481 IWineD3DSwapChain_Release(swapchain);
6485 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6486 IWineD3DSwapChain *swapchain;
6488 TRACE("Relaying to swapchain\n");
6490 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6491 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6492 IWineD3DSwapChain_Release(swapchain);
6497 /** ********************************************************
6498 * Notification functions
6499 ** ********************************************************/
6500 /** This function must be called in the release of a resource when ref == 0,
6501 * the contents of resource must still be correct,
6502 * any handles to other resource held by the caller must be closed
6503 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6504 *****************************************************/
6505 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6507 TRACE("(%p) : Adding resource %p\n", This, resource);
6509 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6512 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6514 TRACE("(%p) : Removing resource %p\n", This, resource);
6516 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6519 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6521 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6522 unsigned int i;
6524 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6526 context_resource_released(device, resource, type);
6528 switch (type)
6530 case WINED3DRTYPE_SURFACE:
6531 if (!device->d3d_initialized) break;
6533 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6535 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6537 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6538 device->render_targets[i] = NULL;
6542 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6544 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6545 device->depth_stencil = NULL;
6547 break;
6549 case WINED3DRTYPE_TEXTURE:
6550 case WINED3DRTYPE_CUBETEXTURE:
6551 case WINED3DRTYPE_VOLUMETEXTURE:
6552 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6554 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6556 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6557 resource, device->stateBlock, i);
6558 device->stateBlock->state.textures[i] = NULL;
6561 if (device->updateStateBlock != device->stateBlock
6562 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6564 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6565 resource, device->updateStateBlock, i);
6566 device->updateStateBlock->state.textures[i] = NULL;
6569 break;
6571 case WINED3DRTYPE_BUFFER:
6572 for (i = 0; i < MAX_STREAMS; ++i)
6574 if (device->stateBlock
6575 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6577 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6578 resource, device->stateBlock, i);
6579 device->stateBlock->state.streams[i].buffer = NULL;
6582 if (device->updateStateBlock != device->stateBlock
6583 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6585 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6586 resource, device->updateStateBlock, i);
6587 device->updateStateBlock->state.streams[i].buffer = NULL;
6592 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6594 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6595 resource, device->stateBlock);
6596 device->stateBlock->state.index_buffer = NULL;
6599 if (device->updateStateBlock != device->stateBlock
6600 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6602 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6603 resource, device->updateStateBlock);
6604 device->updateStateBlock->state.index_buffer = NULL;
6606 break;
6608 default:
6609 break;
6612 /* Remove the resource from the resourceStore */
6613 device_resource_remove(device, resource);
6615 TRACE("Resource released.\n");
6618 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6620 IWineD3DResourceImpl *resource, *cursor;
6621 HRESULT ret;
6622 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6624 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6625 TRACE("enumerating resource %p\n", resource);
6626 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6627 ret = pCallback((IWineD3DResource *) resource, pData);
6628 if(ret == S_FALSE) {
6629 TRACE("Canceling enumeration\n");
6630 break;
6633 return WINED3D_OK;
6636 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6639 IWineD3DResourceImpl *resource;
6641 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6643 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6644 if (type == WINED3DRTYPE_SURFACE)
6646 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6648 TRACE("Found surface %p for dc %p.\n", resource, dc);
6649 *surface = (IWineD3DSurface *)resource;
6650 return WINED3D_OK;
6655 return WINED3DERR_INVALIDCALL;
6658 /**********************************************************
6659 * IWineD3DDevice VTbl follows
6660 **********************************************************/
6662 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6664 /*** IUnknown methods ***/
6665 IWineD3DDeviceImpl_QueryInterface,
6666 IWineD3DDeviceImpl_AddRef,
6667 IWineD3DDeviceImpl_Release,
6668 /*** IWineD3DDevice methods ***/
6669 /*** Creation methods**/
6670 IWineD3DDeviceImpl_CreateBuffer,
6671 IWineD3DDeviceImpl_CreateVertexBuffer,
6672 IWineD3DDeviceImpl_CreateIndexBuffer,
6673 IWineD3DDeviceImpl_CreateStateBlock,
6674 IWineD3DDeviceImpl_CreateSurface,
6675 IWineD3DDeviceImpl_CreateRendertargetView,
6676 IWineD3DDeviceImpl_CreateTexture,
6677 IWineD3DDeviceImpl_CreateVolumeTexture,
6678 IWineD3DDeviceImpl_CreateVolume,
6679 IWineD3DDeviceImpl_CreateCubeTexture,
6680 IWineD3DDeviceImpl_CreateQuery,
6681 IWineD3DDeviceImpl_CreateSwapChain,
6682 IWineD3DDeviceImpl_CreateVertexDeclaration,
6683 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6684 IWineD3DDeviceImpl_CreateVertexShader,
6685 IWineD3DDeviceImpl_CreateGeometryShader,
6686 IWineD3DDeviceImpl_CreatePixelShader,
6687 IWineD3DDeviceImpl_CreatePalette,
6688 /*** Odd functions **/
6689 IWineD3DDeviceImpl_Init3D,
6690 IWineD3DDeviceImpl_InitGDI,
6691 IWineD3DDeviceImpl_Uninit3D,
6692 IWineD3DDeviceImpl_UninitGDI,
6693 IWineD3DDeviceImpl_SetMultithreaded,
6694 IWineD3DDeviceImpl_EvictManagedResources,
6695 IWineD3DDeviceImpl_GetAvailableTextureMem,
6696 IWineD3DDeviceImpl_GetBackBuffer,
6697 IWineD3DDeviceImpl_GetCreationParameters,
6698 IWineD3DDeviceImpl_GetDeviceCaps,
6699 IWineD3DDeviceImpl_GetDirect3D,
6700 IWineD3DDeviceImpl_GetDisplayMode,
6701 IWineD3DDeviceImpl_SetDisplayMode,
6702 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6703 IWineD3DDeviceImpl_GetRasterStatus,
6704 IWineD3DDeviceImpl_GetSwapChain,
6705 IWineD3DDeviceImpl_Reset,
6706 IWineD3DDeviceImpl_SetDialogBoxMode,
6707 IWineD3DDeviceImpl_SetCursorProperties,
6708 IWineD3DDeviceImpl_SetCursorPosition,
6709 IWineD3DDeviceImpl_ShowCursor,
6710 /*** Getters and setters **/
6711 IWineD3DDeviceImpl_SetClipPlane,
6712 IWineD3DDeviceImpl_GetClipPlane,
6713 IWineD3DDeviceImpl_SetClipStatus,
6714 IWineD3DDeviceImpl_GetClipStatus,
6715 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6716 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6717 IWineD3DDeviceImpl_SetDepthStencilSurface,
6718 IWineD3DDeviceImpl_GetDepthStencilSurface,
6719 IWineD3DDeviceImpl_SetGammaRamp,
6720 IWineD3DDeviceImpl_GetGammaRamp,
6721 IWineD3DDeviceImpl_SetIndexBuffer,
6722 IWineD3DDeviceImpl_GetIndexBuffer,
6723 IWineD3DDeviceImpl_SetBaseVertexIndex,
6724 IWineD3DDeviceImpl_GetBaseVertexIndex,
6725 IWineD3DDeviceImpl_SetLight,
6726 IWineD3DDeviceImpl_GetLight,
6727 IWineD3DDeviceImpl_SetLightEnable,
6728 IWineD3DDeviceImpl_GetLightEnable,
6729 IWineD3DDeviceImpl_SetMaterial,
6730 IWineD3DDeviceImpl_GetMaterial,
6731 IWineD3DDeviceImpl_SetNPatchMode,
6732 IWineD3DDeviceImpl_GetNPatchMode,
6733 IWineD3DDeviceImpl_SetPaletteEntries,
6734 IWineD3DDeviceImpl_GetPaletteEntries,
6735 IWineD3DDeviceImpl_SetPixelShader,
6736 IWineD3DDeviceImpl_GetPixelShader,
6737 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6738 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6739 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6740 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6741 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6742 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6743 IWineD3DDeviceImpl_SetRenderState,
6744 IWineD3DDeviceImpl_GetRenderState,
6745 IWineD3DDeviceImpl_SetRenderTarget,
6746 IWineD3DDeviceImpl_GetRenderTarget,
6747 IWineD3DDeviceImpl_SetSamplerState,
6748 IWineD3DDeviceImpl_GetSamplerState,
6749 IWineD3DDeviceImpl_SetScissorRect,
6750 IWineD3DDeviceImpl_GetScissorRect,
6751 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6752 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6753 IWineD3DDeviceImpl_SetStreamSource,
6754 IWineD3DDeviceImpl_GetStreamSource,
6755 IWineD3DDeviceImpl_SetStreamSourceFreq,
6756 IWineD3DDeviceImpl_GetStreamSourceFreq,
6757 IWineD3DDeviceImpl_SetTexture,
6758 IWineD3DDeviceImpl_GetTexture,
6759 IWineD3DDeviceImpl_SetTextureStageState,
6760 IWineD3DDeviceImpl_GetTextureStageState,
6761 IWineD3DDeviceImpl_SetTransform,
6762 IWineD3DDeviceImpl_GetTransform,
6763 IWineD3DDeviceImpl_SetVertexDeclaration,
6764 IWineD3DDeviceImpl_GetVertexDeclaration,
6765 IWineD3DDeviceImpl_SetVertexShader,
6766 IWineD3DDeviceImpl_GetVertexShader,
6767 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6768 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6769 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6770 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6771 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6772 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6773 IWineD3DDeviceImpl_SetViewport,
6774 IWineD3DDeviceImpl_GetViewport,
6775 IWineD3DDeviceImpl_MultiplyTransform,
6776 IWineD3DDeviceImpl_ValidateDevice,
6777 IWineD3DDeviceImpl_ProcessVertices,
6778 /*** State block ***/
6779 IWineD3DDeviceImpl_BeginStateBlock,
6780 IWineD3DDeviceImpl_EndStateBlock,
6781 /*** Scene management ***/
6782 IWineD3DDeviceImpl_BeginScene,
6783 IWineD3DDeviceImpl_EndScene,
6784 IWineD3DDeviceImpl_Present,
6785 IWineD3DDeviceImpl_Clear,
6786 IWineD3DDeviceImpl_ClearRendertargetView,
6787 /*** Drawing ***/
6788 IWineD3DDeviceImpl_SetPrimitiveType,
6789 IWineD3DDeviceImpl_GetPrimitiveType,
6790 IWineD3DDeviceImpl_DrawPrimitive,
6791 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6792 IWineD3DDeviceImpl_DrawPrimitiveUP,
6793 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6794 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6795 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6796 IWineD3DDeviceImpl_DrawRectPatch,
6797 IWineD3DDeviceImpl_DrawTriPatch,
6798 IWineD3DDeviceImpl_DeletePatch,
6799 IWineD3DDeviceImpl_ColorFill,
6800 IWineD3DDeviceImpl_UpdateTexture,
6801 IWineD3DDeviceImpl_UpdateSurface,
6802 IWineD3DDeviceImpl_GetFrontBufferData,
6803 /*** object tracking ***/
6804 IWineD3DDeviceImpl_EnumResources,
6805 IWineD3DDeviceImpl_GetSurfaceFromDC,
6806 IWineD3DDeviceImpl_AcquireFocusWindow,
6807 IWineD3DDeviceImpl_ReleaseFocusWindow,
6810 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6811 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6812 IWineD3DDeviceParent *device_parent)
6814 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6815 const struct fragment_pipeline *fragment_pipeline;
6816 struct shader_caps shader_caps;
6817 struct fragment_caps ffp_caps;
6818 WINED3DDISPLAYMODE mode;
6819 unsigned int i;
6820 HRESULT hr;
6822 device->lpVtbl = &IWineD3DDevice_Vtbl;
6823 device->ref = 1;
6824 device->wined3d = (IWineD3D *)wined3d;
6825 IWineD3D_AddRef(device->wined3d);
6826 device->adapter = wined3d->adapter_count ? adapter : NULL;
6827 device->device_parent = device_parent;
6828 list_init(&device->resources);
6829 list_init(&device->shaders);
6831 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6832 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6834 /* Get the initial screen setup for ddraw. */
6835 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6836 if (FAILED(hr))
6838 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6839 IWineD3D_Release(device->wined3d);
6840 return hr;
6842 device->ddraw_width = mode.Width;
6843 device->ddraw_height = mode.Height;
6844 device->ddraw_format = mode.Format;
6846 /* Save the creation parameters. */
6847 device->createParms.AdapterOrdinal = adapter_idx;
6848 device->createParms.DeviceType = device_type;
6849 device->createParms.hFocusWindow = focus_window;
6850 device->createParms.BehaviorFlags = flags;
6852 device->devType = device_type;
6853 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6855 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6856 device->shader_backend = adapter->shader_backend;
6858 if (device->shader_backend)
6860 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6861 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6862 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6863 device->vs_clipping = shader_caps.VSClipping;
6865 fragment_pipeline = adapter->fragment_pipe;
6866 device->frag_pipe = fragment_pipeline;
6867 if (fragment_pipeline)
6869 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6870 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6872 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6873 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6874 if (FAILED(hr))
6876 ERR("Failed to compile state table, hr %#x.\n", hr);
6877 IWineD3D_Release(device->wined3d);
6878 return hr;
6881 device->blitter = adapter->blitter;
6883 return WINED3D_OK;
6887 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6888 DWORD rep = This->StateTable[state].representative;
6889 struct wined3d_context *context;
6890 DWORD idx;
6891 BYTE shift;
6892 UINT i;
6894 for(i = 0; i < This->numContexts; i++) {
6895 context = This->contexts[i];
6896 if(isStateDirty(context, rep)) continue;
6898 context->dirtyArray[context->numDirtyEntries++] = rep;
6899 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6900 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6901 context->isStateDirty[idx] |= (1 << shift);
6905 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6907 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6908 *width = context->current_rt->pow2Width;
6909 *height = context->current_rt->pow2Height;
6912 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6914 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6915 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6916 * current context's drawable, which is the size of the back buffer of the swapchain
6917 * the active context belongs to. */
6918 *width = swapchain->presentParms.BackBufferWidth;
6919 *height = swapchain->presentParms.BackBufferHeight;
6922 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6923 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6925 if (device->filter_messages)
6927 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6928 window, message, wparam, lparam);
6929 return DefWindowProcW(window, message, wparam, lparam);
6932 if (message == WM_DESTROY)
6934 TRACE("unregister window %p.\n", window);
6935 wined3d_unregister_window(window);
6937 if (device->focus_window == window) device->focus_window = NULL;
6938 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6941 return CallWindowProcW(proc, window, message, wparam, lparam);