wined3d: Pass an IWineD3DDeviceImpl pointer to drawPrimitive().
[wine.git] / dlls / wined3d / device.c
blob5e8c8ccdb9a6dfe0b83cb957ec91a84c5fceff32
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009-2010 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
181 unsigned int i;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
210 buffer_object = 0;
211 data = (BYTE *)buffer;
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((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 LONG fullscreen_style(LONG style)
1755 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1756 style |= WS_POPUP | WS_SYSMENU;
1757 style &= ~(WS_CAPTION | WS_THICKFRAME);
1759 return style;
1762 static LONG fullscreen_exstyle(LONG exstyle)
1764 /* Filter out window decorations. */
1765 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1767 return exstyle;
1770 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h)
1772 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1773 BOOL filter_messages;
1774 LONG style, exstyle;
1776 TRACE("Setting up window %p for fullscreen mode.\n", window);
1778 if (device->style || device->exStyle)
1780 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1781 window, device->style, device->exStyle);
1784 device->style = GetWindowLongW(window, GWL_STYLE);
1785 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1787 style = fullscreen_style(device->style);
1788 exstyle = fullscreen_exstyle(device->exStyle);
1790 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1791 device->style, device->exStyle, style, exstyle);
1793 filter_messages = device->filter_messages;
1794 device->filter_messages = TRUE;
1796 SetWindowLongW(window, GWL_STYLE, style);
1797 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1798 SetWindowPos(window, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1800 device->filter_messages = filter_messages;
1803 static void WINAPI IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice *iface, HWND window)
1805 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1806 BOOL filter_messages;
1807 LONG style, exstyle;
1809 if (!device->style && !device->exStyle) return;
1811 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1812 window, device->style, device->exStyle);
1814 style = GetWindowLongW(window, GWL_STYLE);
1815 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1817 filter_messages = device->filter_messages;
1818 device->filter_messages = TRUE;
1820 /* Only restore the style if the application didn't modify it during the
1821 * fullscreen phase. Some applications change it before calling Reset()
1822 * when switching between windowed and fullscreen modes (HL2), some
1823 * depend on the original style (Eve Online). */
1824 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1826 SetWindowLongW(window, GWL_STYLE, device->style);
1827 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1829 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1831 device->filter_messages = filter_messages;
1833 /* Delete the old values. */
1834 device->style = 0;
1835 device->exStyle = 0;
1838 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1840 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1842 TRACE("iface %p, window %p.\n", iface, window);
1844 if (!wined3d_register_window(window, device))
1846 ERR("Failed to register window %p.\n", window);
1847 return E_FAIL;
1850 device->focus_window = window;
1851 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1853 return WINED3D_OK;
1856 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1858 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1860 TRACE("iface %p.\n", iface);
1862 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1863 device->focus_window = NULL;
1866 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1867 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1870 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1871 IWineD3DSwapChainImpl *swapchain = NULL;
1872 struct wined3d_context *context;
1873 HRESULT hr;
1874 DWORD state;
1875 unsigned int i;
1877 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1879 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1880 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1882 TRACE("(%p) : Creating stateblock\n", This);
1883 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1884 if (FAILED(hr))
1886 WARN("Failed to create stateblock\n");
1887 goto err_out;
1889 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1890 This->updateStateBlock = This->stateBlock;
1891 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1893 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1894 sizeof(*This->render_targets) * gl_info->limits.buffers);
1896 This->NumberOfPalettes = 1;
1897 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1898 if (!This->palettes || !This->render_targets)
1900 ERR("Out of memory!\n");
1901 hr = E_OUTOFMEMORY;
1902 goto err_out;
1904 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1905 if(!This->palettes[0]) {
1906 ERR("Out of memory!\n");
1907 hr = E_OUTOFMEMORY;
1908 goto err_out;
1910 for (i = 0; i < 256; ++i) {
1911 This->palettes[0][i].peRed = 0xFF;
1912 This->palettes[0][i].peGreen = 0xFF;
1913 This->palettes[0][i].peBlue = 0xFF;
1914 This->palettes[0][i].peFlags = 0xFF;
1916 This->currentPalette = 0;
1918 /* Initialize the texture unit mapping to a 1:1 mapping */
1919 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1921 if (state < gl_info->limits.fragment_samplers)
1923 This->texUnitMap[state] = state;
1924 This->rev_tex_unit_map[state] = state;
1925 } else {
1926 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1927 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1931 /* Setup the implicit swapchain. This also initializes a context. */
1932 TRACE("Creating implicit swapchain\n");
1933 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1934 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1935 if (FAILED(hr))
1937 WARN("Failed to create implicit swapchain\n");
1938 goto err_out;
1941 This->NumberOfSwapChains = 1;
1942 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1943 if(!This->swapchains) {
1944 ERR("Out of memory!\n");
1945 goto err_out;
1947 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1949 if (swapchain->back_buffers && swapchain->back_buffers[0])
1951 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1952 This->render_targets[0] = swapchain->back_buffers[0];
1954 else
1956 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1957 This->render_targets[0] = swapchain->front_buffer;
1959 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1961 /* Depth Stencil support */
1962 This->depth_stencil = This->auto_depth_stencil;
1963 if (This->depth_stencil)
1964 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1966 hr = This->shader_backend->shader_alloc_private(iface);
1967 if(FAILED(hr)) {
1968 TRACE("Shader private data couldn't be allocated\n");
1969 goto err_out;
1971 hr = This->frag_pipe->alloc_private(iface);
1972 if(FAILED(hr)) {
1973 TRACE("Fragment pipeline private data couldn't be allocated\n");
1974 goto err_out;
1976 hr = This->blitter->alloc_private(iface);
1977 if(FAILED(hr)) {
1978 TRACE("Blitter private data couldn't be allocated\n");
1979 goto err_out;
1982 /* Set up some starting GL setup */
1984 /* Setup all the devices defaults */
1985 stateblock_init_default_state(This->stateBlock);
1987 context = context_acquire(This, swapchain->front_buffer);
1989 create_dummy_textures(This);
1991 ENTER_GL();
1993 /* Initialize the current view state */
1994 This->view_ident = 1;
1995 This->contexts[0]->last_was_rhw = 0;
1996 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1997 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1999 switch(wined3d_settings.offscreen_rendering_mode) {
2000 case ORM_FBO:
2001 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
2002 break;
2004 case ORM_BACKBUFFER:
2006 if (context_get_current()->aux_buffers > 0)
2008 TRACE("Using auxilliary buffer for offscreen rendering\n");
2009 This->offscreenBuffer = GL_AUX0;
2010 } else {
2011 TRACE("Using back buffer for offscreen rendering\n");
2012 This->offscreenBuffer = GL_BACK;
2017 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2018 LEAVE_GL();
2020 context_release(context);
2022 /* Clear the screen */
2023 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2024 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2025 0x00, 1.0f, 0);
2027 This->d3d_initialized = TRUE;
2029 if(wined3d_settings.logo) {
2030 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2032 This->highest_dirty_ps_const = 0;
2033 This->highest_dirty_vs_const = 0;
2034 return WINED3D_OK;
2036 err_out:
2037 HeapFree(GetProcessHeap(), 0, This->render_targets);
2038 HeapFree(GetProcessHeap(), 0, This->swapchains);
2039 This->NumberOfSwapChains = 0;
2040 if(This->palettes) {
2041 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2042 HeapFree(GetProcessHeap(), 0, This->palettes);
2044 This->NumberOfPalettes = 0;
2045 if(swapchain) {
2046 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2048 if(This->stateBlock) {
2049 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2050 This->stateBlock = NULL;
2052 if (This->blit_priv) {
2053 This->blitter->free_private(iface);
2055 if (This->fragment_priv) {
2056 This->frag_pipe->free_private(iface);
2058 if (This->shader_priv) {
2059 This->shader_backend->shader_free_private(iface);
2061 return hr;
2064 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2065 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2068 IWineD3DSwapChainImpl *swapchain = NULL;
2069 HRESULT hr;
2071 /* Setup the implicit swapchain */
2072 TRACE("Creating implicit swapchain\n");
2073 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2074 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2075 if (FAILED(hr))
2077 WARN("Failed to create implicit swapchain\n");
2078 goto err_out;
2081 This->NumberOfSwapChains = 1;
2082 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2083 if(!This->swapchains) {
2084 ERR("Out of memory!\n");
2085 goto err_out;
2087 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2088 return WINED3D_OK;
2090 err_out:
2091 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2092 return hr;
2095 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2097 IWineD3DResource_UnLoad(resource);
2098 IWineD3DResource_Release(resource);
2099 return WINED3D_OK;
2102 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2103 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2106 const struct wined3d_gl_info *gl_info;
2107 struct wined3d_context *context;
2108 int sampler;
2109 UINT i;
2110 TRACE("(%p)\n", This);
2112 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2114 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2115 * it was created. Thus make sure a context is active for the glDelete* calls
2117 context = context_acquire(This, NULL);
2118 gl_info = context->gl_info;
2120 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2122 /* Unload resources */
2123 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2125 TRACE("Deleting high order patches\n");
2126 for(i = 0; i < PATCHMAP_SIZE; i++) {
2127 struct list *e1, *e2;
2128 struct WineD3DRectPatch *patch;
2129 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2130 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2131 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2135 /* Delete the mouse cursor texture */
2136 if(This->cursorTexture) {
2137 ENTER_GL();
2138 glDeleteTextures(1, &This->cursorTexture);
2139 LEAVE_GL();
2140 This->cursorTexture = 0;
2143 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2144 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2146 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2147 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2150 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2151 * private data, it might contain opengl pointers
2153 if(This->depth_blt_texture) {
2154 ENTER_GL();
2155 glDeleteTextures(1, &This->depth_blt_texture);
2156 LEAVE_GL();
2157 This->depth_blt_texture = 0;
2159 if (This->depth_blt_rb) {
2160 ENTER_GL();
2161 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2162 LEAVE_GL();
2163 This->depth_blt_rb = 0;
2164 This->depth_blt_rb_w = 0;
2165 This->depth_blt_rb_h = 0;
2168 /* Release the update stateblock */
2169 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2170 if(This->updateStateBlock != This->stateBlock)
2171 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2173 This->updateStateBlock = NULL;
2175 { /* because were not doing proper internal refcounts releasing the primary state block
2176 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2177 to set this->stateBlock = NULL; first */
2178 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2179 This->stateBlock = NULL;
2181 /* Release the stateblock */
2182 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2183 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2187 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2188 This->blitter->free_private(iface);
2189 This->frag_pipe->free_private(iface);
2190 This->shader_backend->shader_free_private(iface);
2192 /* Release the buffers (with sanity checks)*/
2193 if (This->onscreen_depth_stencil)
2195 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2196 This->onscreen_depth_stencil = NULL;
2199 if (This->depth_stencil)
2201 IWineD3DSurfaceImpl *ds = This->depth_stencil;
2203 TRACE("Releasing depth/stencil buffer %p.\n", ds);
2205 This->depth_stencil = NULL;
2206 if (IWineD3DSurface_Release((IWineD3DSurface *)ds)
2207 && ds != This->auto_depth_stencil)
2209 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", ds);
2213 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2214 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2216 TRACE("Setting rendertarget to NULL\n");
2217 This->render_targets[0] = NULL;
2219 if (This->auto_depth_stencil)
2221 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2223 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2225 This->auto_depth_stencil = NULL;
2228 context_release(context);
2230 for(i=0; i < This->NumberOfSwapChains; i++) {
2231 TRACE("Releasing the implicit swapchain %d\n", i);
2232 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2233 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2237 HeapFree(GetProcessHeap(), 0, This->swapchains);
2238 This->swapchains = NULL;
2239 This->NumberOfSwapChains = 0;
2241 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2242 HeapFree(GetProcessHeap(), 0, This->palettes);
2243 This->palettes = NULL;
2244 This->NumberOfPalettes = 0;
2246 HeapFree(GetProcessHeap(), 0, This->render_targets);
2247 This->render_targets = NULL;
2249 This->d3d_initialized = FALSE;
2251 return WINED3D_OK;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2256 unsigned int i;
2258 for(i=0; i < This->NumberOfSwapChains; i++) {
2259 TRACE("Releasing the implicit swapchain %d\n", i);
2260 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2261 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2265 HeapFree(GetProcessHeap(), 0, This->swapchains);
2266 This->swapchains = NULL;
2267 This->NumberOfSwapChains = 0;
2268 return WINED3D_OK;
2271 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2272 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2273 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2275 * There is no way to deactivate thread safety once it is enabled.
2277 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2280 /*For now just store the flag(needed in case of ddraw) */
2281 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2284 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2285 const WINED3DDISPLAYMODE* pMode) {
2286 DEVMODEW devmode;
2287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2288 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2289 LONG ret;
2290 RECT clip_rc;
2292 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2294 /* Resize the screen even without a window:
2295 * The app could have unset it with SetCooperativeLevel, but not called
2296 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2297 * but we don't have any hwnd
2300 memset(&devmode, 0, sizeof(devmode));
2301 devmode.dmSize = sizeof(devmode);
2302 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2303 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2304 devmode.dmPelsWidth = pMode->Width;
2305 devmode.dmPelsHeight = pMode->Height;
2307 devmode.dmDisplayFrequency = pMode->RefreshRate;
2308 if (pMode->RefreshRate)
2309 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2311 /* Only change the mode if necessary */
2312 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2313 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2314 return WINED3D_OK;
2316 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2317 if (ret != DISP_CHANGE_SUCCESSFUL)
2319 if (devmode.dmDisplayFrequency)
2321 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2322 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2323 devmode.dmDisplayFrequency = 0;
2324 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2326 if(ret != DISP_CHANGE_SUCCESSFUL) {
2327 return WINED3DERR_NOTAVAILABLE;
2331 /* Store the new values */
2332 This->ddraw_width = pMode->Width;
2333 This->ddraw_height = pMode->Height;
2334 This->ddraw_format = pMode->Format;
2336 /* And finally clip mouse to our screen */
2337 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2338 ClipCursor(&clip_rc);
2340 return WINED3D_OK;
2343 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 *ppD3D = This->wined3d;
2346 TRACE("Returning %p.\n", *ppD3D);
2347 IWineD3D_AddRef(*ppD3D);
2348 return WINED3D_OK;
2351 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2354 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2355 (This->adapter->TextureRam/(1024*1024)),
2356 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2357 /* return simulated texture memory left */
2358 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2361 /*****
2362 * Get / Set Stream Source
2363 *****/
2364 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2365 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 struct wined3d_stream_state *stream;
2369 IWineD3DBuffer *oldSrc;
2371 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2372 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2374 if (StreamNumber >= MAX_STREAMS) {
2375 WARN("Stream out of range %d\n", StreamNumber);
2376 return WINED3DERR_INVALIDCALL;
2377 } else if(OffsetInBytes & 0x3) {
2378 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2379 return WINED3DERR_INVALIDCALL;
2382 stream = &This->updateStateBlock->state.streams[StreamNumber];
2383 oldSrc = (IWineD3DBuffer *)stream->buffer;
2385 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2387 if (oldSrc == pStreamData
2388 && stream->stride == Stride
2389 && stream->offset == OffsetInBytes)
2391 TRACE("Application is setting the old values over, nothing to do\n");
2392 return WINED3D_OK;
2395 stream->buffer = (struct wined3d_buffer *)pStreamData;
2396 if (pStreamData)
2398 stream->stride = Stride;
2399 stream->offset = OffsetInBytes;
2402 /* Handle recording of state blocks */
2403 if (This->isRecordingState) {
2404 TRACE("Recording... not performing anything\n");
2405 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2406 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2407 return WINED3D_OK;
2410 if (pStreamData)
2412 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2413 IWineD3DBuffer_AddRef(pStreamData);
2415 if (oldSrc)
2417 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2418 IWineD3DBuffer_Release(oldSrc);
2421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2423 return WINED3D_OK;
2426 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2427 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 struct wined3d_stream_state *stream;
2432 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2433 iface, StreamNumber, pStream, pOffset, pStride);
2435 if (StreamNumber >= MAX_STREAMS)
2437 WARN("Stream out of range %d\n", StreamNumber);
2438 return WINED3DERR_INVALIDCALL;
2441 stream = &This->stateBlock->state.streams[StreamNumber];
2442 *pStream = (IWineD3DBuffer *)stream->buffer;
2443 *pStride = stream->stride;
2444 if (pOffset) *pOffset = stream->offset;
2446 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2448 return WINED3D_OK;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 struct wined3d_stream_state *stream;
2454 UINT old_flags, oldFreq;
2456 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2458 /* Verify input at least in d3d9 this is invalid. */
2459 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2461 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2462 return WINED3DERR_INVALIDCALL;
2464 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2466 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2467 return WINED3DERR_INVALIDCALL;
2469 if (!Divider)
2471 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2472 return WINED3DERR_INVALIDCALL;
2475 stream = &This->updateStateBlock->state.streams[StreamNumber];
2476 old_flags = stream->flags;
2477 oldFreq = stream->frequency;
2479 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2480 stream->frequency = Divider & 0x7FFFFF;
2482 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2484 if (stream->frequency != oldFreq || stream->flags != old_flags)
2485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2487 return WINED3D_OK;
2490 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 struct wined3d_stream_state *stream;
2494 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2496 stream = &This->updateStateBlock->state.streams[StreamNumber];
2497 *Divider = stream->flags | stream->frequency;
2499 TRACE("Returning %#x.\n", *Divider);
2501 return WINED3D_OK;
2504 /*****
2505 * Get / Set & Multiply Transform
2506 *****/
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 /* Most of this routine, comments included copied from ddraw tree initially: */
2511 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2513 /* Handle recording of state blocks */
2514 if (This->isRecordingState) {
2515 TRACE("Recording... not performing anything\n");
2516 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2517 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2518 return WINED3D_OK;
2522 * If the new matrix is the same as the current one,
2523 * we cut off any further processing. this seems to be a reasonable
2524 * optimization because as was noticed, some apps (warcraft3 for example)
2525 * tend towards setting the same matrix repeatedly for some reason.
2527 * From here on we assume that the new matrix is different, wherever it matters.
2529 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2531 TRACE("The app is setting the same matrix over again\n");
2532 return WINED3D_OK;
2534 else
2536 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2540 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2541 where ViewMat = Camera space, WorldMat = world space.
2543 In OpenGL, camera and world space is combined into GL_MODELVIEW
2544 matrix. The Projection matrix stay projection matrix.
2547 /* Capture the times we can just ignore the change for now */
2548 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2549 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2550 /* Handled by the state manager */
2553 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2556 return WINED3D_OK;
2560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2561 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2563 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2565 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2567 *matrix = device->stateBlock->state.transforms[state];
2569 return WINED3D_OK;
2572 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2573 const WINED3DMATRIX *mat = NULL;
2574 WINED3DMATRIX temp;
2576 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2577 * below means it will be recorded in a state block change, but it
2578 * works regardless where it is recorded.
2579 * If this is found to be wrong, change to StateBlock.
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2584 if (State <= HIGHEST_TRANSFORMSTATE)
2586 mat = &This->updateStateBlock->state.transforms[State];
2588 else
2590 FIXME("Unhandled transform state!!\n");
2593 multiply_matrix(&temp, mat, pMatrix);
2595 /* Apply change via set transform - will reapply to eg. lights this way */
2596 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2599 /*****
2600 * Get / Set Light
2601 *****/
2602 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2603 you can reference any indexes you want as long as that number max are enabled at any
2604 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2605 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2606 but when recording, just build a chain pretty much of commands to be replayed. */
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2609 float rho;
2610 struct wined3d_light_info *object = NULL;
2611 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2612 struct list *e;
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2617 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2618 * the gl driver.
2620 if(!pLight) {
2621 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2622 return WINED3DERR_INVALIDCALL;
2625 switch(pLight->Type) {
2626 case WINED3DLIGHT_POINT:
2627 case WINED3DLIGHT_SPOT:
2628 case WINED3DLIGHT_PARALLELPOINT:
2629 case WINED3DLIGHT_GLSPOT:
2630 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2631 * most wanted
2633 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2635 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2636 return WINED3DERR_INVALIDCALL;
2638 break;
2640 case WINED3DLIGHT_DIRECTIONAL:
2641 /* Ignores attenuation */
2642 break;
2644 default:
2645 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2646 return WINED3DERR_INVALIDCALL;
2649 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2651 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2652 if(object->OriginalIndex == Index) break;
2653 object = NULL;
2656 if(!object) {
2657 TRACE("Adding new light\n");
2658 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2659 if(!object) {
2660 ERR("Out of memory error when allocating a light\n");
2661 return E_OUTOFMEMORY;
2663 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2664 object->glIndex = -1;
2665 object->OriginalIndex = Index;
2668 /* Initialize the object */
2669 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2670 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2671 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2672 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2673 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2674 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2675 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2677 /* Save away the information */
2678 object->OriginalParms = *pLight;
2680 switch (pLight->Type) {
2681 case WINED3DLIGHT_POINT:
2682 /* Position */
2683 object->lightPosn[0] = pLight->Position.x;
2684 object->lightPosn[1] = pLight->Position.y;
2685 object->lightPosn[2] = pLight->Position.z;
2686 object->lightPosn[3] = 1.0f;
2687 object->cutoff = 180.0f;
2688 /* FIXME: Range */
2689 break;
2691 case WINED3DLIGHT_DIRECTIONAL:
2692 /* Direction */
2693 object->lightPosn[0] = -pLight->Direction.x;
2694 object->lightPosn[1] = -pLight->Direction.y;
2695 object->lightPosn[2] = -pLight->Direction.z;
2696 object->lightPosn[3] = 0.0f;
2697 object->exponent = 0.0f;
2698 object->cutoff = 180.0f;
2699 break;
2701 case WINED3DLIGHT_SPOT:
2702 /* Position */
2703 object->lightPosn[0] = pLight->Position.x;
2704 object->lightPosn[1] = pLight->Position.y;
2705 object->lightPosn[2] = pLight->Position.z;
2706 object->lightPosn[3] = 1.0f;
2708 /* Direction */
2709 object->lightDirn[0] = pLight->Direction.x;
2710 object->lightDirn[1] = pLight->Direction.y;
2711 object->lightDirn[2] = pLight->Direction.z;
2712 object->lightDirn[3] = 1.0f;
2715 * opengl-ish and d3d-ish spot lights use too different models for the
2716 * light "intensity" as a function of the angle towards the main light direction,
2717 * so we only can approximate very roughly.
2718 * however spot lights are rather rarely used in games (if ever used at all).
2719 * furthermore if still used, probably nobody pays attention to such details.
2721 if (!pLight->Falloff)
2723 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2724 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2725 * will always be 1.0 for both of them, and we don't have to care for the
2726 * rest of the rather complex calculation
2728 object->exponent = 0.0f;
2729 } else {
2730 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2731 if (rho < 0.0001f) rho = 0.0001f;
2732 object->exponent = -0.3f/logf(cosf(rho/2));
2734 if (object->exponent > 128.0f)
2736 object->exponent = 128.0f;
2738 object->cutoff = (float) (pLight->Phi*90/M_PI);
2740 /* FIXME: Range */
2741 break;
2743 default:
2744 FIXME("Unrecognized light type %d\n", pLight->Type);
2747 /* Update the live definitions if the light is currently assigned a glIndex */
2748 if (object->glIndex != -1 && !This->isRecordingState) {
2749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2751 return WINED3D_OK;
2754 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2756 struct wined3d_light_info *lightInfo = NULL;
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2759 struct list *e;
2760 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2762 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2764 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2765 if(lightInfo->OriginalIndex == Index) break;
2766 lightInfo = NULL;
2769 if (!lightInfo)
2771 TRACE("Light information requested but light not defined\n");
2772 return WINED3DERR_INVALIDCALL;
2775 *pLight = lightInfo->OriginalParms;
2776 return WINED3D_OK;
2779 /*****
2780 * Get / Set Light Enable
2781 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2782 *****/
2783 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2785 struct wined3d_light_info *lightInfo = NULL;
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2788 struct list *e;
2789 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2791 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2793 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2794 if(lightInfo->OriginalIndex == Index) break;
2795 lightInfo = NULL;
2797 TRACE("Found light: %p\n", lightInfo);
2799 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2800 if (!lightInfo)
2802 TRACE("Light enabled requested but light not defined, so defining one!\n");
2803 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2805 /* Search for it again! Should be fairly quick as near head of list */
2806 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2808 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2809 if(lightInfo->OriginalIndex == Index) break;
2810 lightInfo = NULL;
2812 if (!lightInfo)
2814 FIXME("Adding default lights has failed dismally\n");
2815 return WINED3DERR_INVALIDCALL;
2819 if(!Enable) {
2820 if(lightInfo->glIndex != -1) {
2821 if(!This->isRecordingState) {
2822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2825 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2826 lightInfo->glIndex = -1;
2827 } else {
2828 TRACE("Light already disabled, nothing to do\n");
2830 lightInfo->enabled = FALSE;
2831 } else {
2832 lightInfo->enabled = TRUE;
2833 if (lightInfo->glIndex != -1) {
2834 /* nop */
2835 TRACE("Nothing to do as light was enabled\n");
2836 } else {
2837 int i;
2838 /* Find a free gl light */
2839 for (i = 0; i < This->maxConcurrentLights; ++i)
2841 if (!This->updateStateBlock->state.lights[i])
2843 This->updateStateBlock->state.lights[i] = lightInfo;
2844 lightInfo->glIndex = i;
2845 break;
2848 if(lightInfo->glIndex == -1) {
2849 /* Our tests show that Windows returns D3D_OK in this situation, even with
2850 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2851 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2852 * as well for those lights.
2854 * TODO: Test how this affects rendering
2856 WARN("Too many concurrently active lights\n");
2857 return WINED3D_OK;
2860 /* i == lightInfo->glIndex */
2861 if(!This->isRecordingState) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2867 return WINED3D_OK;
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2872 struct wined3d_light_info *lightInfo = NULL;
2873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2874 struct list *e;
2875 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2876 TRACE("(%p) : for idx(%d)\n", This, Index);
2878 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2880 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2881 if(lightInfo->OriginalIndex == Index) break;
2882 lightInfo = NULL;
2885 if (!lightInfo)
2887 TRACE("Light enabled state requested but light not defined\n");
2888 return WINED3DERR_INVALIDCALL;
2890 /* true is 128 according to SetLightEnable */
2891 *pEnable = lightInfo->enabled ? 128 : 0;
2892 return WINED3D_OK;
2895 /*****
2896 * Get / Set Clip Planes
2897 *****/
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2902 /* Validate Index */
2903 if (Index >= This->adapter->gl_info.limits.clipplanes)
2905 TRACE("Application has requested clipplane this device doesn't support\n");
2906 return WINED3DERR_INVALIDCALL;
2909 This->updateStateBlock->changed.clipplane |= 1 << Index;
2911 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2912 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2913 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2914 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2916 TRACE("Application is setting old values over, nothing to do\n");
2917 return WINED3D_OK;
2920 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2921 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2922 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2923 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2925 /* Handle recording of state blocks */
2926 if (This->isRecordingState) {
2927 TRACE("Recording... not performing anything\n");
2928 return WINED3D_OK;
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 TRACE("(%p) : for idx %d\n", This, Index);
2940 /* Validate Index */
2941 if (Index >= This->adapter->gl_info.limits.clipplanes)
2943 TRACE("Application has requested clipplane this device doesn't support\n");
2944 return WINED3DERR_INVALIDCALL;
2947 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2948 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2949 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2950 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2951 return WINED3D_OK;
2954 /*****
2955 * Get / Set Clip Plane Status
2956 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2957 *****/
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 FIXME("(%p) : stub\n", This);
2962 if (!pClipStatus)
2963 return WINED3DERR_INVALIDCALL;
2965 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2966 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 FIXME("(%p) : stub\n", This);
2974 if (!pClipStatus)
2975 return WINED3DERR_INVALIDCALL;
2977 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2978 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2979 return WINED3D_OK;
2982 /*****
2983 * Get / Set Material
2984 *****/
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 This->updateStateBlock->changed.material = TRUE;
2989 This->updateStateBlock->state.material = *pMaterial;
2991 /* Handle recording of state blocks */
2992 if (This->isRecordingState) {
2993 TRACE("Recording... not performing anything\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 *pMaterial = This->updateStateBlock->state.material;
3004 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3005 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3006 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3007 pMaterial->Ambient.b, pMaterial->Ambient.a);
3008 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3009 pMaterial->Specular.b, pMaterial->Specular.a);
3010 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3011 pMaterial->Emissive.b, pMaterial->Emissive.a);
3012 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3014 return WINED3D_OK;
3017 /*****
3018 * Get / Set Indices
3019 *****/
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3021 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 IWineD3DBuffer *oldIdxs;
3026 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3027 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
3029 This->updateStateBlock->changed.indices = TRUE;
3030 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
3031 This->updateStateBlock->state.index_format = fmt;
3033 /* Handle recording of state blocks */
3034 if (This->isRecordingState) {
3035 TRACE("Recording... not performing anything\n");
3036 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3037 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3038 return WINED3D_OK;
3041 if(oldIdxs != pIndexData) {
3042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3043 if(pIndexData) {
3044 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3045 IWineD3DBuffer_AddRef(pIndexData);
3047 if(oldIdxs) {
3048 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3049 IWineD3DBuffer_Release(oldIdxs);
3053 return WINED3D_OK;
3056 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
3062 /* up ref count on ppindexdata */
3063 if (*ppIndexData) {
3064 IWineD3DBuffer_AddRef(*ppIndexData);
3065 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3066 }else{
3067 TRACE("(%p) No index data set\n", This);
3069 TRACE("Returning %p\n", *ppIndexData);
3071 return WINED3D_OK;
3074 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3075 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 TRACE("(%p)->(%d)\n", This, BaseIndex);
3079 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
3081 TRACE("Application is setting the old value over, nothing to do\n");
3082 return WINED3D_OK;
3085 This->updateStateBlock->state.base_vertex_index = BaseIndex;
3087 if (This->isRecordingState) {
3088 TRACE("Recording... not performing anything\n");
3089 return WINED3D_OK;
3091 /* The base vertex index affects the stream sources */
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 TRACE("(%p) : base_index %p\n", This, base_index);
3100 *base_index = This->stateBlock->state.base_vertex_index;
3102 TRACE("Returning %u\n", *base_index);
3104 return WINED3D_OK;
3107 /*****
3108 * Get / Set Viewports
3109 *****/
3110 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3113 TRACE("(%p)\n", This);
3114 This->updateStateBlock->changed.viewport = TRUE;
3115 This->updateStateBlock->state.viewport = *pViewport;
3117 /* Handle recording of state blocks */
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3123 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3124 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3127 return WINED3D_OK;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 TRACE("(%p)\n", This);
3134 *pViewport = This->stateBlock->state.viewport;
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3139 WINED3DRENDERSTATETYPE State, DWORD Value)
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 DWORD oldValue = This->stateBlock->state.render_states[State];
3144 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3146 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3147 This->updateStateBlock->state.render_states[State] = Value;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3152 return WINED3D_OK;
3155 /* Compared here and not before the assignment to allow proper stateblock recording */
3156 if(Value == oldValue) {
3157 TRACE("Application is setting the old value over, nothing to do\n");
3158 } else {
3159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3162 return WINED3D_OK;
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3166 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3172 *pValue = This->stateBlock->state.render_states[State];
3173 return WINED3D_OK;
3176 /*****
3177 * Get / Set Sampler States
3178 * TODO: Verify against dx9 definitions
3179 *****/
3181 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 DWORD oldValue;
3185 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3186 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3188 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3189 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3192 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3194 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3195 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3198 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3199 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3200 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3202 /* Handle recording of state blocks */
3203 if (This->isRecordingState) {
3204 TRACE("Recording... not performing anything\n");
3205 return WINED3D_OK;
3208 if(oldValue == Value) {
3209 TRACE("Application is setting the old value over, nothing to do\n");
3210 return WINED3D_OK;
3213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3215 return WINED3D_OK;
3218 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3222 This, Sampler, debug_d3dsamplerstate(Type), Type);
3224 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3225 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3228 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3230 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3231 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3233 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3234 TRACE("(%p) : Returning %#x\n", This, *Value);
3236 return WINED3D_OK;
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 This->updateStateBlock->changed.scissorRect = TRUE;
3243 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3245 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3246 return WINED3D_OK;
3248 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3250 if(This->isRecordingState) {
3251 TRACE("Recording... not performing anything\n");
3252 return WINED3D_OK;
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 *pRect = This->updateStateBlock->state.scissor_rect;
3264 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3265 return WINED3D_OK;
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3270 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3272 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3274 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3275 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3277 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3278 This->updateStateBlock->changed.vertexDecl = TRUE;
3280 if (This->isRecordingState) {
3281 TRACE("Recording... not performing anything\n");
3282 return WINED3D_OK;
3283 } else if(pDecl == oldDecl) {
3284 /* Checked after the assignment to allow proper stateblock recording */
3285 TRACE("Application is setting the old declaration over, nothing to do\n");
3286 return WINED3D_OK;
3289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3290 return WINED3D_OK;
3293 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3298 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3299 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3300 return WINED3D_OK;
3303 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3308 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3309 This->updateStateBlock->changed.vertexShader = TRUE;
3311 if (This->isRecordingState) {
3312 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3313 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3314 TRACE("Recording... not performing anything\n");
3315 return WINED3D_OK;
3316 } else if(oldShader == pShader) {
3317 /* Checked here to allow proper stateblock recording */
3318 TRACE("App is setting the old shader over, nothing to do\n");
3319 return WINED3D_OK;
3322 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3323 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3324 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3328 return WINED3D_OK;
3331 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3333 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3334 IWineD3DVertexShader *shader;
3336 TRACE("iface %p.\n", iface);
3338 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3339 if (shader) IWineD3DVertexShader_AddRef(shader);
3341 TRACE("Returning %p.\n", shader);
3342 return shader;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3346 IWineD3DDevice *iface,
3347 UINT start,
3348 CONST BOOL *srcData,
3349 UINT count) {
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3354 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3355 iface, srcData, start, count);
3357 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3359 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3360 for (i = 0; i < cnt; i++)
3361 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3363 for (i = start; i < cnt + start; ++i) {
3364 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3367 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3369 return WINED3D_OK;
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3373 IWineD3DDevice *iface,
3374 UINT start,
3375 BOOL *dstData,
3376 UINT count) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 int cnt = min(count, MAX_CONST_B - start);
3381 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3382 iface, dstData, start, count);
3384 if (!dstData || cnt < 0)
3385 return WINED3DERR_INVALIDCALL;
3387 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3388 return WINED3D_OK;
3391 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3392 IWineD3DDevice *iface,
3393 UINT start,
3394 CONST int *srcData,
3395 UINT count) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3400 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3401 iface, srcData, start, count);
3403 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3405 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3406 for (i = 0; i < cnt; i++)
3407 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3408 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3410 for (i = start; i < cnt + start; ++i) {
3411 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3414 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3416 return WINED3D_OK;
3419 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3420 IWineD3DDevice *iface,
3421 UINT start,
3422 int *dstData,
3423 UINT count) {
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 int cnt = min(count, MAX_CONST_I - start);
3428 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3429 iface, dstData, start, count);
3431 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3432 return WINED3DERR_INVALIDCALL;
3434 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3435 return WINED3D_OK;
3438 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3439 IWineD3DDevice *iface,
3440 UINT start,
3441 CONST float *srcData,
3442 UINT count) {
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 UINT i;
3447 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3448 iface, srcData, start, count);
3450 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3451 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3452 return WINED3DERR_INVALIDCALL;
3454 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3455 if(TRACE_ON(d3d)) {
3456 for (i = 0; i < count; i++)
3457 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3458 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3461 if (!This->isRecordingState)
3463 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3467 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3468 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3470 return WINED3D_OK;
3473 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3474 IWineD3DDevice *iface,
3475 UINT start,
3476 float *dstData,
3477 UINT count) {
3479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 int cnt = min(count, This->d3d_vshader_constantF - start);
3482 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3483 iface, dstData, start, count);
3485 if (!dstData || cnt < 0)
3486 return WINED3DERR_INVALIDCALL;
3488 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3489 return WINED3D_OK;
3492 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3493 DWORD i;
3494 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3500 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3502 DWORD i = This->rev_tex_unit_map[unit];
3503 DWORD j = This->texUnitMap[stage];
3505 This->texUnitMap[stage] = unit;
3506 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3508 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3511 This->rev_tex_unit_map[unit] = stage;
3512 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3514 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3518 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3519 int i;
3521 This->fixed_function_usage_map = 0;
3522 for (i = 0; i < MAX_TEXTURES; ++i)
3524 const struct wined3d_state *state = &This->stateBlock->state;
3525 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3526 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3527 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3528 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3529 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3530 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3531 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3532 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3534 if (color_op == WINED3DTOP_DISABLE) {
3535 /* Not used, and disable higher stages */
3536 break;
3539 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3540 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3541 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3542 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3543 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3544 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3545 This->fixed_function_usage_map |= (1 << i);
3548 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3549 This->fixed_function_usage_map |= (1 << (i + 1));
3554 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3556 unsigned int i, tex;
3557 WORD ffu_map;
3559 device_update_fixed_function_usage_map(This);
3560 ffu_map = This->fixed_function_usage_map;
3562 if (This->max_ffp_textures == gl_info->limits.texture_stages
3563 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3565 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3567 if (!(ffu_map & 1)) continue;
3569 if (This->texUnitMap[i] != i) {
3570 device_map_stage(This, i, i);
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3572 markTextureStagesDirty(This, i);
3575 return;
3578 /* Now work out the mapping */
3579 tex = 0;
3580 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3582 if (!(ffu_map & 1)) continue;
3584 if (This->texUnitMap[i] != tex) {
3585 device_map_stage(This, i, tex);
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3587 markTextureStagesDirty(This, i);
3590 ++tex;
3594 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3596 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3597 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3598 unsigned int i;
3600 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3601 if (sampler_type[i] && This->texUnitMap[i] != i)
3603 device_map_stage(This, i, i);
3604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3605 if (i < gl_info->limits.texture_stages)
3607 markTextureStagesDirty(This, i);
3613 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3614 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3616 DWORD current_mapping = This->rev_tex_unit_map[unit];
3618 /* Not currently used */
3619 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3621 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3622 /* Used by a fragment sampler */
3624 if (!pshader_sampler_tokens) {
3625 /* No pixel shader, check fixed function */
3626 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3629 /* Pixel shader, check the shader's sampler map */
3630 return !pshader_sampler_tokens[current_mapping];
3633 /* Used by a vertex sampler */
3634 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3637 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3639 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3640 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3641 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3642 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3643 int i;
3645 if (ps)
3647 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3649 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3650 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3651 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3654 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3655 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3656 if (vshader_sampler_type[i])
3658 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3660 /* Already mapped somewhere */
3661 continue;
3664 while (start >= 0) {
3665 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3667 device_map_stage(This, vsampler_idx, start);
3668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3670 --start;
3671 break;
3674 --start;
3680 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3682 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3683 const struct wined3d_state *state = &This->stateBlock->state;
3684 BOOL vs = use_vs(state);
3685 BOOL ps = use_ps(state);
3687 * Rules are:
3688 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3689 * that would be really messy and require shader recompilation
3690 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3691 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3693 if (ps) device_map_psamplers(This, gl_info);
3694 else device_map_fixed_function_samplers(This, gl_info);
3696 if (vs) device_map_vsamplers(This, ps, gl_info);
3699 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3703 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3704 This->updateStateBlock->changed.pixelShader = TRUE;
3706 /* Handle recording of state blocks */
3707 if (This->isRecordingState) {
3708 TRACE("Recording... not performing anything\n");
3711 if (This->isRecordingState) {
3712 TRACE("Recording... not performing anything\n");
3713 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3714 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3715 return WINED3D_OK;
3718 if(pShader == oldShader) {
3719 TRACE("App is setting the old pixel shader over, nothing to do\n");
3720 return WINED3D_OK;
3723 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3724 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3726 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3729 return WINED3D_OK;
3732 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3734 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3735 IWineD3DPixelShader *shader;
3737 TRACE("iface %p.\n", iface);
3739 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3740 if (shader) IWineD3DPixelShader_AddRef(shader);
3742 TRACE("Returning %p.\n", shader);
3743 return shader;
3746 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3747 IWineD3DDevice *iface,
3748 UINT start,
3749 CONST BOOL *srcData,
3750 UINT count) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3755 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3756 iface, srcData, start, count);
3758 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3760 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3761 for (i = 0; i < cnt; i++)
3762 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3764 for (i = start; i < cnt + start; ++i) {
3765 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3768 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3770 return WINED3D_OK;
3773 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3774 IWineD3DDevice *iface,
3775 UINT start,
3776 BOOL *dstData,
3777 UINT count) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 int cnt = min(count, MAX_CONST_B - start);
3782 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3783 iface, dstData, start, count);
3785 if (!dstData || cnt < 0)
3786 return WINED3DERR_INVALIDCALL;
3788 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3789 return WINED3D_OK;
3792 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3793 IWineD3DDevice *iface,
3794 UINT start,
3795 CONST int *srcData,
3796 UINT count) {
3798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3799 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3801 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3802 iface, srcData, start, count);
3804 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3806 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3807 for (i = 0; i < cnt; i++)
3808 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3809 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3811 for (i = start; i < cnt + start; ++i) {
3812 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3815 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3817 return WINED3D_OK;
3820 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3821 IWineD3DDevice *iface,
3822 UINT start,
3823 int *dstData,
3824 UINT count) {
3826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3827 int cnt = min(count, MAX_CONST_I - start);
3829 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3830 iface, dstData, start, count);
3832 if (!dstData || cnt < 0)
3833 return WINED3DERR_INVALIDCALL;
3835 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3836 return WINED3D_OK;
3839 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3840 IWineD3DDevice *iface,
3841 UINT start,
3842 CONST float *srcData,
3843 UINT count) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 UINT i;
3848 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3849 iface, srcData, start, count);
3851 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3852 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3853 return WINED3DERR_INVALIDCALL;
3855 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3856 if(TRACE_ON(d3d)) {
3857 for (i = 0; i < count; i++)
3858 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3859 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3862 if (!This->isRecordingState)
3864 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3868 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3869 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3875 IWineD3DDevice *iface,
3876 UINT start,
3877 float *dstData,
3878 UINT count) {
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 int cnt = min(count, This->d3d_pshader_constantF - start);
3883 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3884 iface, dstData, start, count);
3886 if (!dstData || cnt < 0)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3890 return WINED3D_OK;
3893 /* Context activation is done by the caller. */
3894 /* Do not call while under the GL lock. */
3895 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3896 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3897 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3898 DWORD DestFVF)
3900 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3901 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3902 unsigned int i;
3903 WINED3DVIEWPORT vp;
3904 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3905 BOOL doClip;
3906 DWORD numTextures;
3908 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3910 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3913 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3915 ERR("Source has no position mask\n");
3916 return WINED3DERR_INVALIDCALL;
3919 if (!dest->resource.allocatedMemory)
3920 buffer_get_sysmem(dest, gl_info);
3922 /* Get a pointer into the destination vbo(create one if none exists) and
3923 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3925 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3927 dest->flags |= WINED3D_BUFFER_CREATEBO;
3928 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3931 if (dest->buffer_object)
3933 unsigned char extrabytes = 0;
3934 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3935 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3936 * this may write 4 extra bytes beyond the area that should be written
3938 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3939 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3940 if(!dest_conv_addr) {
3941 ERR("Out of memory\n");
3942 /* Continue without storing converted vertices */
3944 dest_conv = dest_conv_addr;
3947 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3949 static BOOL warned = FALSE;
3951 * The clipping code is not quite correct. Some things need
3952 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3953 * so disable clipping for now.
3954 * (The graphics in Half-Life are broken, and my processvertices
3955 * test crashes with IDirect3DDevice3)
3956 doClip = TRUE;
3958 doClip = FALSE;
3959 if(!warned) {
3960 warned = TRUE;
3961 FIXME("Clipping is broken and disabled for now\n");
3963 } else doClip = FALSE;
3964 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3966 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3967 WINED3DTS_VIEW,
3968 &view_mat);
3969 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3970 WINED3DTS_PROJECTION,
3971 &proj_mat);
3972 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3973 WINED3DTS_WORLDMATRIX(0),
3974 &world_mat);
3976 TRACE("View mat:\n");
3977 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3978 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3979 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3980 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3982 TRACE("Proj mat:\n");
3983 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3984 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3985 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3986 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3988 TRACE("World mat:\n");
3989 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3990 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3991 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3992 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3994 /* Get the viewport */
3995 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3996 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3997 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3999 multiply_matrix(&mat,&view_mat,&world_mat);
4000 multiply_matrix(&mat,&proj_mat,&mat);
4002 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4004 for (i = 0; i < dwCount; i+= 1) {
4005 unsigned int tex_index;
4007 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4008 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4009 /* The position first */
4010 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4011 const float *p = (const float *)(element->data + i * element->stride);
4012 float x, y, z, rhw;
4013 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4015 /* Multiplication with world, view and projection matrix */
4016 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
4017 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
4018 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
4019 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
4021 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4023 /* WARNING: The following things are taken from d3d7 and were not yet checked
4024 * against d3d8 or d3d9!
4027 /* Clipping conditions: From msdn
4029 * A vertex is clipped if it does not match the following requirements
4030 * -rhw < x <= rhw
4031 * -rhw < y <= rhw
4032 * 0 < z <= rhw
4033 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4035 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4036 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4040 if( !doClip ||
4041 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4042 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4043 ( rhw > eps ) ) ) {
4045 /* "Normal" viewport transformation (not clipped)
4046 * 1) The values are divided by rhw
4047 * 2) The y axis is negative, so multiply it with -1
4048 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4049 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4050 * 4) Multiply x with Width/2 and add Width/2
4051 * 5) The same for the height
4052 * 6) Add the viewpoint X and Y to the 2D coordinates and
4053 * The minimum Z value to z
4054 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4056 * Well, basically it's simply a linear transformation into viewport
4057 * coordinates
4060 x /= rhw;
4061 y /= rhw;
4062 z /= rhw;
4064 y *= -1;
4066 x *= vp.Width / 2;
4067 y *= vp.Height / 2;
4068 z *= vp.MaxZ - vp.MinZ;
4070 x += vp.Width / 2 + vp.X;
4071 y += vp.Height / 2 + vp.Y;
4072 z += vp.MinZ;
4074 rhw = 1 / rhw;
4075 } else {
4076 /* That vertex got clipped
4077 * Contrary to OpenGL it is not dropped completely, it just
4078 * undergoes a different calculation.
4080 TRACE("Vertex got clipped\n");
4081 x += rhw;
4082 y += rhw;
4084 x /= 2;
4085 y /= 2;
4087 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4088 * outside of the main vertex buffer memory. That needs some more
4089 * investigation...
4093 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4096 ( (float *) dest_ptr)[0] = x;
4097 ( (float *) dest_ptr)[1] = y;
4098 ( (float *) dest_ptr)[2] = z;
4099 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4101 dest_ptr += 3 * sizeof(float);
4103 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4104 dest_ptr += sizeof(float);
4107 if(dest_conv) {
4108 float w = 1 / rhw;
4109 ( (float *) dest_conv)[0] = x * w;
4110 ( (float *) dest_conv)[1] = y * w;
4111 ( (float *) dest_conv)[2] = z * w;
4112 ( (float *) dest_conv)[3] = w;
4114 dest_conv += 3 * sizeof(float);
4116 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4117 dest_conv += sizeof(float);
4121 if (DestFVF & WINED3DFVF_PSIZE) {
4122 dest_ptr += sizeof(DWORD);
4123 if(dest_conv) dest_conv += sizeof(DWORD);
4125 if (DestFVF & WINED3DFVF_NORMAL) {
4126 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4127 const float *normal = (const float *)(element->data + i * element->stride);
4128 /* AFAIK this should go into the lighting information */
4129 FIXME("Didn't expect the destination to have a normal\n");
4130 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4131 if(dest_conv) {
4132 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4136 if (DestFVF & WINED3DFVF_DIFFUSE) {
4137 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4138 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4139 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4141 static BOOL warned = FALSE;
4143 if(!warned) {
4144 ERR("No diffuse color in source, but destination has one\n");
4145 warned = TRUE;
4148 *( (DWORD *) dest_ptr) = 0xffffffff;
4149 dest_ptr += sizeof(DWORD);
4151 if(dest_conv) {
4152 *( (DWORD *) dest_conv) = 0xffffffff;
4153 dest_conv += sizeof(DWORD);
4156 else {
4157 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4158 if(dest_conv) {
4159 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4160 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4161 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4162 dest_conv += sizeof(DWORD);
4167 if (DestFVF & WINED3DFVF_SPECULAR)
4169 /* What's the color value in the feedback buffer? */
4170 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4171 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4172 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4174 static BOOL warned = FALSE;
4176 if(!warned) {
4177 ERR("No specular color in source, but destination has one\n");
4178 warned = TRUE;
4181 *( (DWORD *) dest_ptr) = 0xFF000000;
4182 dest_ptr += sizeof(DWORD);
4184 if(dest_conv) {
4185 *( (DWORD *) dest_conv) = 0xFF000000;
4186 dest_conv += sizeof(DWORD);
4189 else {
4190 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4191 if(dest_conv) {
4192 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4193 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4194 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4195 dest_conv += sizeof(DWORD);
4200 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4201 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4202 const float *tex_coord = (const float *)(element->data + i * element->stride);
4203 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4205 ERR("No source texture, but destination requests one\n");
4206 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4207 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4209 else {
4210 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4211 if(dest_conv) {
4212 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4218 if (dest_conv)
4220 ENTER_GL();
4222 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4223 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4224 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4225 dwCount * get_flexible_vertex_size(DestFVF),
4226 dest_conv_addr));
4227 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4229 LEAVE_GL();
4231 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4234 return WINED3D_OK;
4236 #undef copy_and_next
4238 /* Do not call while under the GL lock. */
4239 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4240 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD flags,
4241 DWORD DestFVF)
4243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4244 struct wined3d_stream_info stream_info;
4245 const struct wined3d_gl_info *gl_info;
4246 struct wined3d_context *context;
4247 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4248 HRESULT hr;
4250 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, flags);
4252 if(pVertexDecl) {
4253 ERR("Output vertex declaration not implemented yet\n");
4256 /* Need any context to write to the vbo. */
4257 context = context_acquire(This, NULL);
4258 gl_info = context->gl_info;
4260 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4261 * control the streamIsUP flag, thus restore it afterwards.
4263 This->stateBlock->state.user_stream = FALSE;
4264 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4265 This->stateBlock->state.user_stream = streamWasUP;
4267 if(vbo || SrcStartIndex) {
4268 unsigned int i;
4269 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4270 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4272 * Also get the start index in, but only loop over all elements if there's something to add at all.
4274 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4276 struct wined3d_stream_info_element *e;
4278 if (!(stream_info.use_map & (1 << i))) continue;
4280 e = &stream_info.elements[i];
4281 if (e->buffer_object)
4283 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4284 e->buffer_object = 0;
4285 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4286 ENTER_GL();
4287 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4288 vb->buffer_object = 0;
4289 LEAVE_GL();
4291 if (e->data) e->data += e->stride * SrcStartIndex;
4295 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4296 (struct wined3d_buffer *)pDestBuffer, flags, DestFVF);
4298 context_release(context);
4300 return hr;
4303 /*****
4304 * Get / Set Texture Stage States
4305 * TODO: Verify against dx9 definitions
4306 *****/
4307 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4311 DWORD oldValue;
4313 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4315 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4317 WARN("Invalid Type %d passed.\n", Type);
4318 return WINED3D_OK;
4321 if (Stage >= gl_info->limits.texture_stages)
4323 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4324 Stage, gl_info->limits.texture_stages - 1);
4325 return WINED3D_OK;
4328 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4329 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4330 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4332 if (This->isRecordingState) {
4333 TRACE("Recording... not performing anything\n");
4334 return WINED3D_OK;
4337 /* Checked after the assignments to allow proper stateblock recording */
4338 if(oldValue == Value) {
4339 TRACE("App is setting the old value over, nothing to do\n");
4340 return WINED3D_OK;
4343 if (Stage > This->stateBlock->state.lowest_disabled_stage
4344 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4345 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4347 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4348 * Changes in other states are important on disabled stages too
4350 return WINED3D_OK;
4353 if(Type == WINED3DTSS_COLOROP) {
4354 unsigned int i;
4356 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4357 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4358 * they have to be disabled
4360 * The current stage is dirtified below.
4362 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4364 TRACE("Additionally dirtifying stage %u\n", i);
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4367 This->stateBlock->state.lowest_disabled_stage = Stage;
4368 TRACE("New lowest disabled: %u\n", Stage);
4369 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4370 /* Previously disabled stage enabled. Stages above it may need enabling
4371 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4372 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4374 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4377 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4379 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4380 break;
4381 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4384 This->stateBlock->state.lowest_disabled_stage = i;
4385 TRACE("New lowest disabled: %u\n", i);
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4391 return WINED3D_OK;
4394 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4398 TRACE("iface %p, stage %u, state %s, value %p.\n",
4399 iface, Stage, debug_d3dtexturestate(Type), pValue);
4401 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4403 WARN("Invalid Type %d passed.\n", Type);
4404 return WINED3D_OK;
4407 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4408 TRACE("Returning %#x.\n", *pValue);
4410 return WINED3D_OK;
4413 /*****
4414 * Get / Set Texture
4415 *****/
4416 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4417 DWORD stage, IWineD3DBaseTexture *texture)
4419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4420 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4421 IWineD3DBaseTexture *prev;
4423 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4425 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4426 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4428 /* Windows accepts overflowing this array... we do not. */
4429 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4431 WARN("Ignoring invalid stage %u.\n", stage);
4432 return WINED3D_OK;
4435 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4436 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4438 WARN("Rejecting attempt to set scratch texture.\n");
4439 return WINED3DERR_INVALIDCALL;
4442 This->updateStateBlock->changed.textures |= 1 << stage;
4444 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4445 TRACE("Previous texture %p.\n", prev);
4447 if (texture == prev)
4449 TRACE("App is setting the same texture again, nothing to do.\n");
4450 return WINED3D_OK;
4453 TRACE("Setting new texture to %p.\n", texture);
4454 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4456 if (This->isRecordingState)
4458 TRACE("Recording... not performing anything\n");
4460 if (texture) IWineD3DBaseTexture_AddRef(texture);
4461 if (prev) IWineD3DBaseTexture_Release(prev);
4463 return WINED3D_OK;
4466 if (texture)
4468 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4469 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4470 GLenum dimensions = t->baseTexture.target;
4472 IWineD3DBaseTexture_AddRef(texture);
4474 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4477 if (!prev && stage < gl_info->limits.texture_stages)
4479 /* The source arguments for color and alpha ops have different
4480 * meanings when a NULL texture is bound, so the COLOROP and
4481 * ALPHAOP have to be dirtified. */
4482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4486 if (bind_count == 1) t->baseTexture.sampler = stage;
4489 if (prev)
4491 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4492 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4494 IWineD3DBaseTexture_Release(prev);
4496 if (!texture && stage < gl_info->limits.texture_stages)
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4502 if (bind_count && t->baseTexture.sampler == stage)
4504 unsigned int i;
4506 /* Search for other stages the texture is bound to. Shouldn't
4507 * happen if applications bind textures to a single stage only. */
4508 TRACE("Searching for other stages the texture is bound to.\n");
4509 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4511 if (This->updateStateBlock->state.textures[i] == t)
4513 TRACE("Texture is also bound to stage %u.\n", i);
4514 t->baseTexture.sampler = i;
4515 break;
4521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4523 return WINED3D_OK;
4526 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4531 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4532 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4535 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4537 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4538 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4541 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4542 if (*ppTexture)
4543 IWineD3DBaseTexture_AddRef(*ppTexture);
4545 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4547 return WINED3D_OK;
4550 /*****
4551 * Get Back Buffer
4552 *****/
4553 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4554 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4556 IWineD3DSwapChain *swapchain;
4557 HRESULT hr;
4559 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4560 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4562 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4563 if (FAILED(hr))
4565 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4566 return hr;
4569 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4570 IWineD3DSwapChain_Release(swapchain);
4571 if (FAILED(hr))
4573 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4574 return hr;
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 WARN("(%p) : stub, calling idirect3d for now\n", This);
4583 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4586 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 IWineD3DSwapChain *swapChain;
4589 HRESULT hr;
4591 if(iSwapChain > 0) {
4592 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4593 if (hr == WINED3D_OK) {
4594 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4595 IWineD3DSwapChain_Release(swapChain);
4596 } else {
4597 FIXME("(%p) Error getting display mode\n", This);
4599 } else {
4600 /* Don't read the real display mode,
4601 but return the stored mode instead. X11 can't change the color
4602 depth, and some apps are pretty angry if they SetDisplayMode from
4603 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4605 Also don't relay to the swapchain because with ddraw it's possible
4606 that there isn't a swapchain at all */
4607 pMode->Width = This->ddraw_width;
4608 pMode->Height = This->ddraw_height;
4609 pMode->Format = This->ddraw_format;
4610 pMode->RefreshRate = 0;
4611 hr = WINED3D_OK;
4614 return hr;
4617 /*****
4618 * Stateblock related functions
4619 *****/
4621 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 IWineD3DStateBlock *stateblock;
4624 HRESULT hr;
4626 TRACE("(%p)\n", This);
4628 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4630 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4631 if (FAILED(hr)) return hr;
4633 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4634 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4635 This->isRecordingState = TRUE;
4637 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4639 return WINED3D_OK;
4642 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4646 if (!This->isRecordingState) {
4647 WARN("(%p) not recording! returning error\n", This);
4648 *ppStateBlock = NULL;
4649 return WINED3DERR_INVALIDCALL;
4652 stateblock_init_contained_states(object);
4654 *ppStateBlock = (IWineD3DStateBlock*) object;
4655 This->isRecordingState = FALSE;
4656 This->updateStateBlock = This->stateBlock;
4657 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4658 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4660 return WINED3D_OK;
4663 /*****
4664 * Scene related functions
4665 *****/
4666 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4667 /* At the moment we have no need for any functionality at the beginning
4668 of a scene */
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 TRACE("(%p)\n", This);
4672 if(This->inScene) {
4673 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4674 return WINED3DERR_INVALIDCALL;
4676 This->inScene = TRUE;
4677 return WINED3D_OK;
4680 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 struct wined3d_context *context;
4685 TRACE("(%p)\n", This);
4687 if(!This->inScene) {
4688 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4689 return WINED3DERR_INVALIDCALL;
4692 context = context_acquire(This, NULL);
4693 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4694 wglFlush();
4695 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4696 * fails. */
4697 context_release(context);
4699 This->inScene = FALSE;
4700 return WINED3D_OK;
4703 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4704 const RECT *pSourceRect, const RECT *pDestRect,
4705 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4707 IWineD3DSwapChain *swapChain = NULL;
4708 int i;
4709 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4711 TRACE("iface %p.\n", iface);
4713 for(i = 0 ; i < swapchains ; i ++) {
4715 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4716 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4717 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4718 IWineD3DSwapChain_Release(swapChain);
4721 return WINED3D_OK;
4724 /* Do not call while under the GL lock. */
4725 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4726 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4728 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4729 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4730 RECT draw_rect;
4732 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4733 iface, rect_count, rects, flags, color, depth, stencil);
4735 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4737 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4738 /* TODO: What about depth stencil buffers without stencil bits? */
4739 return WINED3DERR_INVALIDCALL;
4742 device_get_draw_rect(device, &draw_rect);
4744 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4745 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4748 /*****
4749 * Drawing functions
4750 *****/
4752 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4753 WINED3DPRIMITIVETYPE primitive_type)
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4759 This->updateStateBlock->changed.primitive_type = TRUE;
4760 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4763 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4764 WINED3DPRIMITIVETYPE *primitive_type)
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4770 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4772 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4775 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4781 if (!This->stateBlock->state.vertex_declaration)
4783 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4784 return WINED3DERR_INVALIDCALL;
4787 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4788 if (This->stateBlock->state.user_stream)
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4791 This->stateBlock->state.user_stream = FALSE;
4794 if (This->stateBlock->state.load_base_vertex_index)
4796 This->stateBlock->state.load_base_vertex_index = 0;
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4799 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4800 drawPrimitive(This, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 struct wined3d_buffer *index_buffer;
4808 UINT idxStride = 2;
4809 GLuint vbo;
4811 index_buffer = This->stateBlock->state.index_buffer;
4812 if (!index_buffer)
4814 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4815 * without an index buffer set. (The first time at least...)
4816 * D3D8 simply dies, but I doubt it can do much harm to return
4817 * D3DERR_INVALIDCALL there as well. */
4818 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4819 return WINED3DERR_INVALIDCALL;
4822 if (!This->stateBlock->state.vertex_declaration)
4824 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4825 return WINED3DERR_INVALIDCALL;
4828 if (This->stateBlock->state.user_stream)
4830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4831 This->stateBlock->state.user_stream = FALSE;
4833 vbo = index_buffer->buffer_object;
4835 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4837 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4838 idxStride = 2;
4839 else
4840 idxStride = 4;
4842 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4844 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4848 drawPrimitive(This, index_count, startIndex, idxStride,
4849 vbo ? NULL : index_buffer->resource.allocatedMemory);
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4855 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4858 struct wined3d_stream_state *stream;
4859 IWineD3DBuffer *vb;
4861 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4862 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4864 if (!This->stateBlock->state.vertex_declaration)
4866 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4867 return WINED3DERR_INVALIDCALL;
4870 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4871 stream = &This->stateBlock->state.streams[0];
4872 vb = (IWineD3DBuffer *)stream->buffer;
4873 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4874 if (vb) IWineD3DBuffer_Release(vb);
4875 stream->offset = 0;
4876 stream->stride = VertexStreamZeroStride;
4877 This->stateBlock->state.user_stream = TRUE;
4878 This->stateBlock->state.load_base_vertex_index = 0;
4880 /* TODO: Only mark dirty if drawing from a different UP address */
4881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4883 drawPrimitive(This, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4885 /* MSDN specifies stream zero settings must be set to NULL */
4886 stream->buffer = NULL;
4887 stream->stride = 0;
4889 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4890 * the new stream sources or use UP drawing again
4892 return WINED3D_OK;
4895 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4896 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4897 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4899 int idxStride;
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 struct wined3d_stream_state *stream;
4902 IWineD3DBuffer *vb;
4903 IWineD3DBuffer *ib;
4905 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4906 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4908 if (!This->stateBlock->state.vertex_declaration)
4910 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4911 return WINED3DERR_INVALIDCALL;
4914 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4915 idxStride = 2;
4916 } else {
4917 idxStride = 4;
4920 stream = &This->stateBlock->state.streams[0];
4921 vb = (IWineD3DBuffer *)stream->buffer;
4922 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4923 if (vb) IWineD3DBuffer_Release(vb);
4924 stream->offset = 0;
4925 stream->stride = VertexStreamZeroStride;
4926 This->stateBlock->state.user_stream = TRUE;
4928 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4929 This->stateBlock->state.base_vertex_index = 0;
4930 This->stateBlock->state.load_base_vertex_index = 0;
4931 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4935 drawPrimitive(This, index_count, 0 /* start_idx */, idxStride, pIndexData);
4937 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4938 stream->buffer = NULL;
4939 stream->stride = 0;
4940 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4941 if (ib)
4943 IWineD3DBuffer_Release(ib);
4944 This->stateBlock->state.index_buffer = NULL;
4946 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4947 * SetStreamSource to specify a vertex buffer
4950 return WINED3D_OK;
4953 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4954 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4958 /* Mark the state dirty until we have nicer tracking
4959 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4960 * that value.
4962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4964 This->stateBlock->state.base_vertex_index = 0;
4965 This->up_strided = DrawPrimStrideData;
4966 drawPrimitive(This, vertex_count, 0, 0, NULL);
4967 This->up_strided = NULL;
4968 return WINED3D_OK;
4971 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4972 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4973 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4976 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4978 /* Mark the state dirty until we have nicer tracking
4979 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4980 * that value.
4982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4983 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4984 This->stateBlock->state.user_stream = TRUE;
4985 This->stateBlock->state.base_vertex_index = 0;
4986 This->up_strided = DrawPrimStrideData;
4987 drawPrimitive(This, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4988 This->up_strided = NULL;
4989 return WINED3D_OK;
4992 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4993 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4994 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4996 WINED3DLOCKED_BOX src;
4997 WINED3DLOCKED_BOX dst;
4998 HRESULT hr;
5000 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5001 iface, pSourceVolume, pDestinationVolume);
5003 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5004 * dirtification to improve loading performance.
5006 hr = IWineD3DVolume_Map(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5007 if (FAILED(hr)) return hr;
5008 hr = IWineD3DVolume_Map(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5009 if (FAILED(hr))
5011 IWineD3DVolume_Unmap(pSourceVolume);
5012 return hr;
5015 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5017 hr = IWineD3DVolume_Unmap(pDestinationVolume);
5018 if (FAILED(hr))
5019 IWineD3DVolume_Unmap(pSourceVolume);
5020 else
5021 hr = IWineD3DVolume_Unmap(pSourceVolume);
5023 return hr;
5026 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5027 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5029 unsigned int level_count, i;
5030 WINED3DRESOURCETYPE type;
5031 HRESULT hr;
5033 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5035 /* Verify that the source and destination textures are non-NULL. */
5036 if (!src_texture || !dst_texture)
5038 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5039 return WINED3DERR_INVALIDCALL;
5042 if (src_texture == dst_texture)
5044 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5045 return WINED3DERR_INVALIDCALL;
5048 /* Verify that the source and destination textures are the same type. */
5049 type = IWineD3DBaseTexture_GetType(src_texture);
5050 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5052 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5053 return WINED3DERR_INVALIDCALL;
5056 /* Check that both textures have the identical numbers of levels. */
5057 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5058 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5060 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5061 return WINED3DERR_INVALIDCALL;
5064 /* Make sure that the destination texture is loaded. */
5065 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5067 /* Update every surface level of the texture. */
5068 switch (type)
5070 case WINED3DRTYPE_TEXTURE:
5072 IWineD3DSurface *src_surface;
5073 IWineD3DSurface *dst_surface;
5075 for (i = 0; i < level_count; ++i)
5077 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5078 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5079 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5080 IWineD3DSurface_Release(dst_surface);
5081 IWineD3DSurface_Release(src_surface);
5082 if (FAILED(hr))
5084 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5085 return hr;
5088 break;
5091 case WINED3DRTYPE_CUBETEXTURE:
5093 IWineD3DSurface *src_surface;
5094 IWineD3DSurface *dst_surface;
5096 for (i = 0; i < level_count * 6; ++i)
5098 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture, i, &src_surface);
5099 if (FAILED(hr)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i, hr);
5100 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture, i, &dst_surface);
5101 if (FAILED(hr)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i, hr);
5102 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5103 IWineD3DSurface_Release(dst_surface);
5104 IWineD3DSurface_Release(src_surface);
5105 if (FAILED(hr))
5107 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5108 return hr;
5111 break;
5114 case WINED3DRTYPE_VOLUMETEXTURE:
5116 IWineD3DVolume *src_volume;
5117 IWineD3DVolume *dst_volume;
5119 for (i = 0; i < level_count; ++i)
5121 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5122 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5123 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5124 IWineD3DVolume_Release(dst_volume);
5125 IWineD3DVolume_Release(src_volume);
5126 if (FAILED(hr))
5128 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5129 return hr;
5132 break;
5135 default:
5136 FIXME("Unsupported texture type %#x.\n", type);
5137 return WINED3DERR_INVALIDCALL;
5140 return WINED3D_OK;
5143 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5144 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5146 IWineD3DSwapChain *swapchain;
5147 HRESULT hr;
5149 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5151 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5152 if (FAILED(hr)) return hr;
5154 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5155 IWineD3DSwapChain_Release(swapchain);
5157 return hr;
5160 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5162 IWineD3DBaseTextureImpl *texture;
5163 DWORD i;
5165 TRACE("(%p) : %p\n", This, pNumPasses);
5167 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5169 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5171 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5172 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5174 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5176 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5177 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5180 texture = This->stateBlock->state.textures[i];
5181 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
5183 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5185 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5186 return E_FAIL;
5188 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5190 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5191 return E_FAIL;
5193 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5194 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5196 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5197 return E_FAIL;
5201 /* return a sensible default */
5202 *pNumPasses = 1;
5204 TRACE("returning D3D_OK\n");
5205 return WINED3D_OK;
5208 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5210 int i;
5212 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5214 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5215 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5216 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5218 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5223 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5225 int j;
5226 UINT NewSize;
5227 PALETTEENTRY **palettes;
5229 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5231 if (PaletteNumber >= MAX_PALETTES) {
5232 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5233 return WINED3DERR_INVALIDCALL;
5236 if (PaletteNumber >= This->NumberOfPalettes) {
5237 NewSize = This->NumberOfPalettes;
5238 do {
5239 NewSize *= 2;
5240 } while(PaletteNumber >= NewSize);
5241 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5242 if (!palettes) {
5243 ERR("Out of memory!\n");
5244 return E_OUTOFMEMORY;
5246 This->palettes = palettes;
5247 This->NumberOfPalettes = NewSize;
5250 if (!This->palettes[PaletteNumber]) {
5251 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5252 if (!This->palettes[PaletteNumber]) {
5253 ERR("Out of memory!\n");
5254 return E_OUTOFMEMORY;
5258 for (j = 0; j < 256; ++j) {
5259 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5260 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5261 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5262 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5264 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5265 TRACE("(%p) : returning\n", This);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 int j;
5272 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5273 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5274 /* What happens in such situation isn't documented; Native seems to silently abort
5275 on such conditions. Return Invalid Call. */
5276 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5277 return WINED3DERR_INVALIDCALL;
5279 for (j = 0; j < 256; ++j) {
5280 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5281 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5282 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5283 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5285 TRACE("(%p) : returning\n", This);
5286 return WINED3D_OK;
5289 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5291 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5292 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5293 (tested with reference rasterizer). Return Invalid Call. */
5294 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5295 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5296 return WINED3DERR_INVALIDCALL;
5298 /*TODO: stateblocks */
5299 if (This->currentPalette != PaletteNumber) {
5300 This->currentPalette = PaletteNumber;
5301 dirtify_p8_texture_samplers(This);
5303 TRACE("(%p) : returning\n", This);
5304 return WINED3D_OK;
5307 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5310 if (!PaletteNumber)
5312 WARN("(%p) : returning Invalid Call\n", This);
5313 return WINED3DERR_INVALIDCALL;
5315 /*TODO: stateblocks */
5316 *PaletteNumber = This->currentPalette;
5317 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5318 return WINED3D_OK;
5321 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5323 static BOOL warned;
5324 if (!warned)
5326 FIXME("(%p) : stub\n", This);
5327 warned = TRUE;
5330 This->softwareVertexProcessing = bSoftware;
5331 return WINED3D_OK;
5335 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 static BOOL warned;
5338 if (!warned)
5340 FIXME("(%p) : stub\n", This);
5341 warned = TRUE;
5343 return This->softwareVertexProcessing;
5346 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5347 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5349 IWineD3DSwapChain *swapchain;
5350 HRESULT hr;
5352 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5353 iface, swapchain_idx, raster_status);
5355 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5356 if (FAILED(hr))
5358 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5359 return hr;
5362 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5363 IWineD3DSwapChain_Release(swapchain);
5364 if (FAILED(hr))
5366 WARN("Failed to get raster status, hr %#x.\n", hr);
5367 return hr;
5370 return WINED3D_OK;
5373 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5375 static BOOL warned;
5376 if(nSegments != 0.0f) {
5377 if (!warned)
5379 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5380 warned = TRUE;
5383 return WINED3D_OK;
5386 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5388 static BOOL warned;
5389 if (!warned)
5391 FIXME("iface %p stub!\n", iface);
5392 warned = TRUE;
5394 return 0.0f;
5397 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5398 IWineD3DSurface *src_surface, const RECT *src_rect,
5399 IWineD3DSurface *dst_surface, const POINT *dst_point)
5401 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5402 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 const struct wined3d_format *src_format;
5405 const struct wined3d_format *dst_format;
5406 const struct wined3d_gl_info *gl_info;
5407 struct wined3d_context *context;
5408 const unsigned char *data;
5409 UINT update_w, update_h;
5410 CONVERT_TYPES convert;
5411 UINT src_w, src_h;
5412 UINT dst_x, dst_y;
5413 DWORD sampler;
5414 struct wined3d_format format;
5416 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5417 iface, src_surface, wine_dbgstr_rect(src_rect),
5418 dst_surface, wine_dbgstr_point(dst_point));
5420 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5422 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5423 src_surface, dst_surface);
5424 return WINED3DERR_INVALIDCALL;
5427 src_format = src_impl->resource.format;
5428 dst_format = dst_impl->resource.format;
5430 if (src_format->id != dst_format->id)
5432 WARN("Source and destination surfaces should have the same format.\n");
5433 return WINED3DERR_INVALIDCALL;
5436 dst_x = dst_point ? dst_point->x : 0;
5437 dst_y = dst_point ? dst_point->y : 0;
5439 /* This call loads the OpenGL surface directly, instead of copying the
5440 * surface to the destination's sysmem copy. If surface conversion is
5441 * needed, use BltFast instead to copy in sysmem and use regular surface
5442 * loading. */
5443 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5444 if (convert != NO_CONVERSION || format.convert)
5445 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5447 context = context_acquire(This, NULL);
5448 gl_info = context->gl_info;
5450 ENTER_GL();
5451 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5452 checkGLcall("glActiveTextureARB");
5453 LEAVE_GL();
5455 /* Make sure the surface is loaded and up to date */
5456 surface_internal_preload(dst_impl, SRGB_RGB);
5457 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5459 src_w = src_impl->currentDesc.Width;
5460 src_h = src_impl->currentDesc.Height;
5461 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5462 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5464 data = IWineD3DSurface_GetData(src_surface);
5465 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5467 ENTER_GL();
5469 if (dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
5471 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5472 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5473 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5475 if (src_rect)
5477 data += (src_rect->top / src_format->block_height) * src_pitch;
5478 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5481 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5482 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5483 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5485 if (row_length == src_pitch)
5487 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5488 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5490 else
5492 UINT row, y;
5494 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5495 * can't use the unpack row length like below. */
5496 for (row = 0, y = dst_y; row < row_count; ++row)
5498 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5499 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5500 y += src_format->block_height;
5501 data += src_pitch;
5504 checkGLcall("glCompressedTexSubImage2DARB");
5506 else
5508 if (src_rect)
5510 data += src_rect->top * src_w * src_format->byte_count;
5511 data += src_rect->left * src_format->byte_count;
5514 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5515 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5516 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5518 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5519 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5520 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5521 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5522 checkGLcall("glTexSubImage2D");
5525 LEAVE_GL();
5526 context_release(context);
5528 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5529 sampler = This->rev_tex_unit_map[0];
5530 if (sampler != WINED3D_UNMAPPED_STAGE)
5532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5535 return WINED3D_OK;
5538 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5540 struct WineD3DRectPatch *patch;
5541 GLenum old_primitive_type;
5542 unsigned int i;
5543 struct list *e;
5544 BOOL found;
5545 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5547 if(!(Handle || pRectPatchInfo)) {
5548 /* TODO: Write a test for the return value, thus the FIXME */
5549 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5550 return WINED3DERR_INVALIDCALL;
5553 if(Handle) {
5554 i = PATCHMAP_HASHFUNC(Handle);
5555 found = FALSE;
5556 LIST_FOR_EACH(e, &This->patches[i]) {
5557 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5558 if(patch->Handle == Handle) {
5559 found = TRUE;
5560 break;
5564 if(!found) {
5565 TRACE("Patch does not exist. Creating a new one\n");
5566 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5567 patch->Handle = Handle;
5568 list_add_head(&This->patches[i], &patch->entry);
5569 } else {
5570 TRACE("Found existing patch %p\n", patch);
5572 } else {
5573 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5574 * attributes we have to tesselate, read back, and draw. This needs a patch
5575 * management structure instance. Create one.
5577 * A possible improvement is to check if a vertex shader is used, and if not directly
5578 * draw the patch.
5580 FIXME("Drawing an uncached patch. This is slow\n");
5581 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5584 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5585 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5586 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5588 HRESULT hr;
5589 TRACE("Tesselation density or patch info changed, retesselating\n");
5591 if(pRectPatchInfo) {
5592 patch->RectPatchInfo = *pRectPatchInfo;
5594 patch->numSegs[0] = pNumSegs[0];
5595 patch->numSegs[1] = pNumSegs[1];
5596 patch->numSegs[2] = pNumSegs[2];
5597 patch->numSegs[3] = pNumSegs[3];
5599 hr = tesselate_rectpatch(This, patch);
5600 if(FAILED(hr)) {
5601 WARN("Patch tesselation failed\n");
5603 /* Do not release the handle to store the params of the patch */
5604 if(!Handle) {
5605 HeapFree(GetProcessHeap(), 0, patch);
5607 return hr;
5611 This->currentPatch = patch;
5612 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5613 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5614 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5615 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5616 This->currentPatch = NULL;
5618 /* Destroy uncached patches */
5619 if(!Handle) {
5620 HeapFree(GetProcessHeap(), 0, patch->mem);
5621 HeapFree(GetProcessHeap(), 0, patch);
5623 return WINED3D_OK;
5626 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5627 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5629 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5630 iface, handle, segment_count, patch_info);
5632 return WINED3D_OK;
5635 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 int i;
5638 struct WineD3DRectPatch *patch;
5639 struct list *e;
5640 TRACE("(%p) Handle(%d)\n", This, Handle);
5642 i = PATCHMAP_HASHFUNC(Handle);
5643 LIST_FOR_EACH(e, &This->patches[i]) {
5644 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5645 if(patch->Handle == Handle) {
5646 TRACE("Deleting patch %p\n", patch);
5647 list_remove(&patch->entry);
5648 HeapFree(GetProcessHeap(), 0, patch->mem);
5649 HeapFree(GetProcessHeap(), 0, patch);
5650 return WINED3D_OK;
5654 /* TODO: Write a test for the return value */
5655 FIXME("Attempt to destroy nonexistent patch\n");
5656 return WINED3DERR_INVALIDCALL;
5659 /* Do not call while under the GL lock. */
5660 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5661 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5663 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5665 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5666 iface, surface, wine_dbgstr_rect(rect),
5667 color->r, color->g, color->b, color->a);
5669 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5671 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5672 return WINED3DERR_INVALIDCALL;
5675 return surface_color_fill(s, rect, color);
5678 /* Do not call while under the GL lock. */
5679 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5680 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5682 IWineD3DResource *resource;
5683 HRESULT hr;
5685 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5686 if (FAILED(hr))
5688 ERR("Failed to get resource, hr %#x\n", hr);
5689 return;
5692 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5694 FIXME("Only supported on surface resources\n");
5695 IWineD3DResource_Release(resource);
5696 return;
5699 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5700 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5702 IWineD3DResource_Release(resource);
5705 /* rendertarget and depth stencil functions */
5706 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5707 DWORD render_target_idx, IWineD3DSurface **render_target)
5709 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5711 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5712 iface, render_target_idx, render_target);
5714 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5716 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5717 return WINED3DERR_INVALIDCALL;
5720 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5721 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5723 TRACE("Returning render target %p.\n", *render_target);
5725 return WINED3D_OK;
5728 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5730 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5732 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5734 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5735 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5736 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5737 IWineD3DSurface_AddRef(*depth_stencil);
5739 return WINED3D_OK;
5742 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5743 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5745 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5746 IWineD3DSurfaceImpl *prev;
5748 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5749 iface, render_target_idx, render_target, set_viewport);
5751 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5753 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5754 return WINED3DERR_INVALIDCALL;
5757 prev = device->render_targets[render_target_idx];
5758 if (render_target == (IWineD3DSurface *)prev)
5760 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5761 return WINED3D_OK;
5764 /* Render target 0 can't be set to NULL. */
5765 if (!render_target && !render_target_idx)
5767 WARN("Trying to set render target 0 to NULL.\n");
5768 return WINED3DERR_INVALIDCALL;
5771 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5773 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5774 return WINED3DERR_INVALIDCALL;
5777 if (render_target) IWineD3DSurface_AddRef(render_target);
5778 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5779 /* Release after the assignment, to prevent device_resource_released()
5780 * from seeing the surface as still in use. */
5781 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5783 /* Render target 0 is special. */
5784 if (!render_target_idx && set_viewport)
5786 /* Set the viewport and scissor rectangles, if requested. Tests show
5787 * that stateblock recording is ignored, the change goes directly
5788 * into the primary stateblock. */
5789 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5790 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5791 device->stateBlock->state.viewport.X = 0;
5792 device->stateBlock->state.viewport.Y = 0;
5793 device->stateBlock->state.viewport.MaxZ = 1.0f;
5794 device->stateBlock->state.viewport.MinZ = 0.0f;
5795 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5797 device->stateBlock->state.scissor_rect.top = 0;
5798 device->stateBlock->state.scissor_rect.left = 0;
5799 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5800 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5801 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5804 return WINED3D_OK;
5807 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5810 IWineD3DSurfaceImpl *tmp;
5812 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5814 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5816 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5817 return WINED3D_OK;
5820 if (This->depth_stencil)
5822 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5823 || This->depth_stencil->flags & SFLAG_DISCARD)
5825 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5826 This->depth_stencil->currentDesc.Width,
5827 This->depth_stencil->currentDesc.Height);
5828 if (This->depth_stencil == This->onscreen_depth_stencil)
5830 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5831 This->onscreen_depth_stencil = NULL;
5836 tmp = This->depth_stencil;
5837 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5838 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5839 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5841 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5843 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5849 return WINED3D_OK;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5853 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5856 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5857 WINED3DLOCKED_RECT lockedRect;
5859 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5860 iface, XHotSpot, YHotSpot, cursor_image);
5862 /* some basic validation checks */
5863 if (This->cursorTexture)
5865 struct wined3d_context *context = context_acquire(This, NULL);
5866 ENTER_GL();
5867 glDeleteTextures(1, &This->cursorTexture);
5868 LEAVE_GL();
5869 context_release(context);
5870 This->cursorTexture = 0;
5873 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5874 This->haveHardwareCursor = TRUE;
5875 else
5876 This->haveHardwareCursor = FALSE;
5878 if (cursor_image)
5880 WINED3DLOCKED_RECT rect;
5882 /* MSDN: Cursor must be A8R8G8B8 */
5883 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5885 WARN("surface %p has an invalid format.\n", cursor_image);
5886 return WINED3DERR_INVALIDCALL;
5889 /* MSDN: Cursor must be smaller than the display mode */
5890 if (s->currentDesc.Width > This->ddraw_width
5891 || s->currentDesc.Height > This->ddraw_height)
5893 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5894 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5895 return WINED3DERR_INVALIDCALL;
5898 if (!This->haveHardwareCursor) {
5899 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5901 /* Do not store the surface's pointer because the application may
5902 * release it after setting the cursor image. Windows doesn't
5903 * addref the set surface, so we can't do this either without
5904 * creating circular refcount dependencies. Copy out the gl texture
5905 * instead.
5907 This->cursorWidth = s->currentDesc.Width;
5908 This->cursorHeight = s->currentDesc.Height;
5909 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5911 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5912 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5913 struct wined3d_context *context;
5914 char *mem, *bits = rect.pBits;
5915 GLint intfmt = format->glInternal;
5916 GLint gl_format = format->glFormat;
5917 GLint type = format->glType;
5918 INT height = This->cursorHeight;
5919 INT width = This->cursorWidth;
5920 INT bpp = format->byte_count;
5921 DWORD sampler;
5922 INT i;
5924 /* Reformat the texture memory (pitch and width can be
5925 * different) */
5926 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5927 for(i = 0; i < height; i++)
5928 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5929 IWineD3DSurface_Unmap(cursor_image);
5931 context = context_acquire(This, NULL);
5933 ENTER_GL();
5935 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5937 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5938 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5941 /* Make sure that a proper texture unit is selected */
5942 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5943 checkGLcall("glActiveTextureARB");
5944 sampler = This->rev_tex_unit_map[0];
5945 if (sampler != WINED3D_UNMAPPED_STAGE)
5947 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5949 /* Create a new cursor texture */
5950 glGenTextures(1, &This->cursorTexture);
5951 checkGLcall("glGenTextures");
5952 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5953 checkGLcall("glBindTexture");
5954 /* Copy the bitmap memory into the cursor texture */
5955 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5956 checkGLcall("glTexImage2D");
5957 HeapFree(GetProcessHeap(), 0, mem);
5959 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5961 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5962 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5965 LEAVE_GL();
5967 context_release(context);
5969 else
5971 FIXME("A cursor texture was not returned.\n");
5972 This->cursorTexture = 0;
5975 else
5977 /* Draw a hardware cursor */
5978 ICONINFO cursorInfo;
5979 HCURSOR cursor;
5980 /* Create and clear maskBits because it is not needed for
5981 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5982 * chunks. */
5983 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5984 (s->currentDesc.Width * s->currentDesc.Height / 8));
5985 IWineD3DSurface_Map(cursor_image, &lockedRect, NULL,
5986 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5987 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5989 cursorInfo.fIcon = FALSE;
5990 cursorInfo.xHotspot = XHotSpot;
5991 cursorInfo.yHotspot = YHotSpot;
5992 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5993 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5994 IWineD3DSurface_Unmap(cursor_image);
5995 /* Create our cursor and clean up. */
5996 cursor = CreateIconIndirect(&cursorInfo);
5997 SetCursor(cursor);
5998 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5999 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6000 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6001 This->hardwareCursor = cursor;
6002 HeapFree(GetProcessHeap(), 0, maskBits);
6006 This->xHotSpot = XHotSpot;
6007 This->yHotSpot = YHotSpot;
6008 return WINED3D_OK;
6011 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice *iface,
6012 int XScreenSpace, int YScreenSpace, DWORD flags)
6014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6016 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6017 iface, XScreenSpace, YScreenSpace, flags);
6019 This->xScreenSpace = XScreenSpace;
6020 This->yScreenSpace = YScreenSpace;
6023 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6025 BOOL oldVisible = This->bCursorVisible;
6026 POINT pt;
6028 TRACE("(%p) : visible(%d)\n", This, bShow);
6031 * When ShowCursor is first called it should make the cursor appear at the OS's last
6032 * known cursor position. Because of this, some applications just repetitively call
6033 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6035 GetCursorPos(&pt);
6036 This->xScreenSpace = pt.x;
6037 This->yScreenSpace = pt.y;
6039 if (This->haveHardwareCursor) {
6040 This->bCursorVisible = bShow;
6041 if (bShow)
6042 SetCursor(This->hardwareCursor);
6043 else
6044 SetCursor(NULL);
6046 else
6048 if (This->cursorTexture)
6049 This->bCursorVisible = bShow;
6052 return oldVisible;
6055 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6056 TRACE("checking resource %p for eviction\n", resource);
6057 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6058 TRACE("Evicting %p\n", resource);
6059 IWineD3DResource_UnLoad(resource);
6061 IWineD3DResource_Release(resource);
6062 return S_OK;
6065 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6067 TRACE("iface %p.\n", iface);
6069 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6070 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6071 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6073 return WINED3D_OK;
6076 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6078 IWineD3DDeviceImpl *device = surface->resource.device;
6079 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6081 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6082 if (surface->flags & SFLAG_DIBSECTION)
6084 /* Release the DC */
6085 SelectObject(surface->hDC, surface->dib.holdbitmap);
6086 DeleteDC(surface->hDC);
6087 /* Release the DIB section */
6088 DeleteObject(surface->dib.DIBsection);
6089 surface->dib.bitmap_data = NULL;
6090 surface->resource.allocatedMemory = NULL;
6091 surface->flags &= ~SFLAG_DIBSECTION;
6093 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6094 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6095 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6096 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6098 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6099 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6100 } else {
6101 surface->pow2Width = surface->pow2Height = 1;
6102 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6103 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6106 if (surface->texture_name)
6108 struct wined3d_context *context = context_acquire(device, NULL);
6109 ENTER_GL();
6110 glDeleteTextures(1, &surface->texture_name);
6111 LEAVE_GL();
6112 context_release(context);
6113 surface->texture_name = 0;
6114 surface->flags &= ~SFLAG_CLIENT;
6116 if (surface->pow2Width != pPresentationParameters->BackBufferWidth
6117 || surface->pow2Height != pPresentationParameters->BackBufferHeight)
6119 surface->flags |= SFLAG_NONPOW2;
6121 else
6123 surface->flags &= ~SFLAG_NONPOW2;
6125 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6126 surface->resource.allocatedMemory = NULL;
6127 surface->resource.heapMemory = NULL;
6128 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6130 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6131 * to a FBO */
6132 if (!surface_init_sysmem(surface))
6134 return E_OUTOFMEMORY;
6136 return WINED3D_OK;
6139 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6140 TRACE("Unloading resource %p\n", resource);
6141 IWineD3DResource_UnLoad(resource);
6142 IWineD3DResource_Release(resource);
6143 return S_OK;
6146 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6148 UINT i, count;
6149 WINED3DDISPLAYMODE m;
6150 HRESULT hr;
6152 /* All Windowed modes are supported, as is leaving the current mode */
6153 if(pp->Windowed) return TRUE;
6154 if(!pp->BackBufferWidth) return TRUE;
6155 if(!pp->BackBufferHeight) return TRUE;
6157 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6158 for(i = 0; i < count; i++) {
6159 memset(&m, 0, sizeof(m));
6160 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6161 if(FAILED(hr)) {
6162 ERR("EnumAdapterModes failed\n");
6164 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6165 /* Mode found, it is supported */
6166 return TRUE;
6169 /* Mode not found -> not supported */
6170 return FALSE;
6173 /* Do not call while under the GL lock. */
6174 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6177 const struct wined3d_gl_info *gl_info;
6178 struct wined3d_context *context;
6179 IWineD3DBaseShaderImpl *shader;
6181 context = context_acquire(This, NULL);
6182 gl_info = context->gl_info;
6184 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6185 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6186 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6189 ENTER_GL();
6190 if(This->depth_blt_texture) {
6191 glDeleteTextures(1, &This->depth_blt_texture);
6192 This->depth_blt_texture = 0;
6194 if (This->depth_blt_rb) {
6195 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6196 This->depth_blt_rb = 0;
6197 This->depth_blt_rb_w = 0;
6198 This->depth_blt_rb_h = 0;
6200 LEAVE_GL();
6202 This->blitter->free_private(iface);
6203 This->frag_pipe->free_private(iface);
6204 This->shader_backend->shader_free_private(iface);
6205 destroy_dummy_textures(This, gl_info);
6207 context_release(context);
6209 while (This->numContexts)
6211 context_destroy(This, This->contexts[0]);
6213 HeapFree(GetProcessHeap(), 0, swapchain->context);
6214 swapchain->context = NULL;
6215 swapchain->num_contexts = 0;
6218 /* Do not call while under the GL lock. */
6219 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6222 struct wined3d_context *context;
6223 HRESULT hr;
6224 IWineD3DSurfaceImpl *target;
6226 /* Recreate the primary swapchain's context */
6227 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6228 if (!swapchain->context)
6230 ERR("Failed to allocate memory for swapchain context array.\n");
6231 return E_OUTOFMEMORY;
6234 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6235 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6237 WARN("Failed to create context.\n");
6238 HeapFree(GetProcessHeap(), 0, swapchain->context);
6239 return E_FAIL;
6242 swapchain->context[0] = context;
6243 swapchain->num_contexts = 1;
6244 create_dummy_textures(This);
6245 context_release(context);
6247 hr = This->shader_backend->shader_alloc_private(iface);
6248 if (FAILED(hr))
6250 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6251 goto err;
6254 hr = This->frag_pipe->alloc_private(iface);
6255 if (FAILED(hr))
6257 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6258 This->shader_backend->shader_free_private(iface);
6259 goto err;
6262 hr = This->blitter->alloc_private(iface);
6263 if (FAILED(hr))
6265 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6266 This->frag_pipe->free_private(iface);
6267 This->shader_backend->shader_free_private(iface);
6268 goto err;
6271 return WINED3D_OK;
6273 err:
6274 context_acquire(This, NULL);
6275 destroy_dummy_textures(This, context->gl_info);
6276 context_release(context);
6277 context_destroy(This, context);
6278 HeapFree(GetProcessHeap(), 0, swapchain->context);
6279 swapchain->num_contexts = 0;
6280 return hr;
6283 /* Do not call while under the GL lock. */
6284 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6285 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6288 IWineD3DSwapChainImpl *swapchain;
6289 HRESULT hr;
6290 BOOL DisplayModeChanged = FALSE;
6291 WINED3DDISPLAYMODE mode;
6292 TRACE("(%p)\n", This);
6294 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6295 if(FAILED(hr)) {
6296 ERR("Failed to get the first implicit swapchain\n");
6297 return hr;
6300 if(!is_display_mode_supported(This, pPresentationParameters)) {
6301 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6302 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6303 pPresentationParameters->BackBufferHeight);
6304 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6305 return WINED3DERR_INVALIDCALL;
6308 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6309 * on an existing gl context, so there's no real need for recreation.
6311 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6313 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6315 TRACE("New params:\n");
6316 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6317 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6318 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6319 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6320 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6321 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6322 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6323 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6324 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6325 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6326 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6327 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6328 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6330 /* No special treatment of these parameters. Just store them */
6331 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6332 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6333 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6334 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6336 /* What to do about these? */
6337 if (pPresentationParameters->BackBufferCount
6338 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6339 ERR("Cannot change the back buffer count yet\n");
6341 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6342 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6343 ERR("Cannot change the back buffer format yet\n");
6346 if (pPresentationParameters->hDeviceWindow
6347 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6348 ERR("Cannot change the device window yet\n");
6350 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6352 HRESULT hrc;
6354 TRACE("Creating the depth stencil buffer\n");
6356 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6357 pPresentationParameters->BackBufferWidth,
6358 pPresentationParameters->BackBufferHeight,
6359 pPresentationParameters->AutoDepthStencilFormat,
6360 pPresentationParameters->MultiSampleType,
6361 pPresentationParameters->MultiSampleQuality,
6362 FALSE,
6363 (IWineD3DSurface **)&This->auto_depth_stencil);
6365 if (FAILED(hrc)) {
6366 ERR("Failed to create the depth stencil buffer\n");
6367 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6368 return WINED3DERR_INVALIDCALL;
6372 if (This->onscreen_depth_stencil)
6374 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6375 This->onscreen_depth_stencil = NULL;
6378 /* Reset the depth stencil */
6379 if (pPresentationParameters->EnableAutoDepthStencil)
6380 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6381 else
6382 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6384 TRACE("Resetting stateblock\n");
6385 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6386 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6388 delete_opengl_contexts(iface, swapchain);
6390 if(pPresentationParameters->Windowed) {
6391 mode.Width = swapchain->orig_width;
6392 mode.Height = swapchain->orig_height;
6393 mode.RefreshRate = 0;
6394 mode.Format = swapchain->presentParms.BackBufferFormat;
6395 } else {
6396 mode.Width = pPresentationParameters->BackBufferWidth;
6397 mode.Height = pPresentationParameters->BackBufferHeight;
6398 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6399 mode.Format = swapchain->presentParms.BackBufferFormat;
6402 /* Should Width == 800 && Height == 0 set 800x600? */
6403 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6404 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6405 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6407 UINT i;
6409 if(!pPresentationParameters->Windowed) {
6410 DisplayModeChanged = TRUE;
6412 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6413 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6415 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6416 if(FAILED(hr))
6418 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6419 return hr;
6422 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6424 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6425 if(FAILED(hr))
6427 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6428 return hr;
6431 if (This->auto_depth_stencil)
6433 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6434 if(FAILED(hr))
6436 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6437 return hr;
6442 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6443 || DisplayModeChanged)
6445 BOOL filter = This->filter_messages;
6446 This->filter_messages = TRUE;
6448 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6450 if (!pPresentationParameters->Windowed)
6452 if (swapchain->presentParms.Windowed)
6454 HWND focus_window = This->createParms.hFocusWindow;
6455 if (!focus_window) focus_window = pPresentationParameters->hDeviceWindow;
6456 if (FAILED(hr = IWineD3DDevice_AcquireFocusWindow(iface, focus_window)))
6458 ERR("Failed to acquire focus window, hr %#x.\n", hr);
6459 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6460 return hr;
6463 /* switch from windowed to fs */
6464 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6465 pPresentationParameters->BackBufferWidth,
6466 pPresentationParameters->BackBufferHeight);
6468 else
6470 /* Fullscreen -> fullscreen mode change */
6471 MoveWindow(swapchain->device_window, 0, 0,
6472 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6473 TRUE);
6476 else if (!swapchain->presentParms.Windowed)
6478 /* Fullscreen -> windowed switch */
6479 IWineD3DDevice_RestoreFullscreenWindow(iface, swapchain->device_window);
6480 IWineD3DDevice_ReleaseFocusWindow(iface);
6482 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6484 This->filter_messages = filter;
6486 else if (!pPresentationParameters->Windowed)
6488 DWORD style = This->style, exStyle = This->exStyle;
6489 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6490 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6491 * Reset to clear up their mess. Guild Wars also loses the device during that.
6493 This->style = 0;
6494 This->exStyle = 0;
6495 IWineD3DDevice_SetupFullscreenWindow(iface, swapchain->device_window,
6496 pPresentationParameters->BackBufferWidth,
6497 pPresentationParameters->BackBufferHeight);
6498 This->style = style;
6499 This->exStyle = exStyle;
6502 /* Note: No parent needed for initial internal stateblock */
6503 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6504 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6505 else TRACE("Created stateblock %p\n", This->stateBlock);
6506 This->updateStateBlock = This->stateBlock;
6507 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6509 stateblock_init_default_state(This->stateBlock);
6511 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6513 RECT client_rect;
6514 GetClientRect(swapchain->win_handle, &client_rect);
6516 if(!swapchain->presentParms.BackBufferCount)
6518 TRACE("Single buffered rendering\n");
6519 swapchain->render_to_fbo = FALSE;
6521 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6522 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6524 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6525 swapchain->presentParms.BackBufferWidth,
6526 swapchain->presentParms.BackBufferHeight,
6527 client_rect.right, client_rect.bottom);
6528 swapchain->render_to_fbo = TRUE;
6530 else
6532 TRACE("Rendering directly to GL_BACK\n");
6533 swapchain->render_to_fbo = FALSE;
6537 hr = create_primary_opengl_context(iface, swapchain);
6538 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6540 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6541 * first use
6543 return hr;
6546 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6548 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6550 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6552 return WINED3D_OK;
6556 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6558 TRACE("(%p) : pParameters %p\n", This, pParameters);
6560 *pParameters = This->createParms;
6561 return WINED3D_OK;
6564 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice *iface,
6565 UINT iSwapChain, DWORD flags, const WINED3DGAMMARAMP *pRamp)
6567 IWineD3DSwapChain *swapchain;
6569 TRACE("Relaying to swapchain\n");
6571 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK)
6573 IWineD3DSwapChain_SetGammaRamp(swapchain, flags, pRamp);
6574 IWineD3DSwapChain_Release(swapchain);
6578 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6579 IWineD3DSwapChain *swapchain;
6581 TRACE("Relaying to swapchain\n");
6583 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6584 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6585 IWineD3DSwapChain_Release(swapchain);
6590 /** ********************************************************
6591 * Notification functions
6592 ** ********************************************************/
6593 /** This function must be called in the release of a resource when ref == 0,
6594 * the contents of resource must still be correct,
6595 * any handles to other resource held by the caller must be closed
6596 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6597 *****************************************************/
6598 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6600 TRACE("(%p) : Adding resource %p\n", This, resource);
6602 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6605 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6607 TRACE("(%p) : Removing resource %p\n", This, resource);
6609 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6612 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6614 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6615 unsigned int i;
6617 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6619 context_resource_released(device, resource, type);
6621 switch (type)
6623 case WINED3DRTYPE_SURFACE:
6624 if (!device->d3d_initialized) break;
6626 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6628 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6630 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6631 device->render_targets[i] = NULL;
6635 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6637 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6638 device->depth_stencil = NULL;
6640 break;
6642 case WINED3DRTYPE_TEXTURE:
6643 case WINED3DRTYPE_CUBETEXTURE:
6644 case WINED3DRTYPE_VOLUMETEXTURE:
6645 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6647 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6649 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6650 resource, device->stateBlock, i);
6651 device->stateBlock->state.textures[i] = NULL;
6654 if (device->updateStateBlock != device->stateBlock
6655 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6657 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6658 resource, device->updateStateBlock, i);
6659 device->updateStateBlock->state.textures[i] = NULL;
6662 break;
6664 case WINED3DRTYPE_BUFFER:
6665 for (i = 0; i < MAX_STREAMS; ++i)
6667 if (device->stateBlock
6668 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6670 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6671 resource, device->stateBlock, i);
6672 device->stateBlock->state.streams[i].buffer = NULL;
6675 if (device->updateStateBlock != device->stateBlock
6676 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6678 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6679 resource, device->updateStateBlock, i);
6680 device->updateStateBlock->state.streams[i].buffer = NULL;
6685 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6687 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6688 resource, device->stateBlock);
6689 device->stateBlock->state.index_buffer = NULL;
6692 if (device->updateStateBlock != device->stateBlock
6693 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6695 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6696 resource, device->updateStateBlock);
6697 device->updateStateBlock->state.index_buffer = NULL;
6699 break;
6701 default:
6702 break;
6705 /* Remove the resource from the resourceStore */
6706 device_resource_remove(device, resource);
6708 TRACE("Resource released.\n");
6711 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6713 IWineD3DResourceImpl *resource, *cursor;
6714 HRESULT ret;
6715 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6717 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6718 TRACE("enumerating resource %p\n", resource);
6719 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6720 ret = pCallback((IWineD3DResource *) resource, pData);
6721 if(ret == S_FALSE) {
6722 TRACE("Canceling enumeration\n");
6723 break;
6726 return WINED3D_OK;
6729 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6732 IWineD3DResourceImpl *resource;
6734 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6736 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6737 if (type == WINED3DRTYPE_SURFACE)
6739 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6741 TRACE("Found surface %p for dc %p.\n", resource, dc);
6742 *surface = (IWineD3DSurface *)resource;
6743 return WINED3D_OK;
6748 return WINED3DERR_INVALIDCALL;
6751 /**********************************************************
6752 * IWineD3DDevice VTbl follows
6753 **********************************************************/
6755 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6757 /*** IUnknown methods ***/
6758 IWineD3DDeviceImpl_QueryInterface,
6759 IWineD3DDeviceImpl_AddRef,
6760 IWineD3DDeviceImpl_Release,
6761 /*** IWineD3DDevice methods ***/
6762 /*** Creation methods**/
6763 IWineD3DDeviceImpl_CreateBuffer,
6764 IWineD3DDeviceImpl_CreateVertexBuffer,
6765 IWineD3DDeviceImpl_CreateIndexBuffer,
6766 IWineD3DDeviceImpl_CreateStateBlock,
6767 IWineD3DDeviceImpl_CreateSurface,
6768 IWineD3DDeviceImpl_CreateRendertargetView,
6769 IWineD3DDeviceImpl_CreateTexture,
6770 IWineD3DDeviceImpl_CreateVolumeTexture,
6771 IWineD3DDeviceImpl_CreateVolume,
6772 IWineD3DDeviceImpl_CreateCubeTexture,
6773 IWineD3DDeviceImpl_CreateQuery,
6774 IWineD3DDeviceImpl_CreateSwapChain,
6775 IWineD3DDeviceImpl_CreateVertexDeclaration,
6776 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6777 IWineD3DDeviceImpl_CreateVertexShader,
6778 IWineD3DDeviceImpl_CreateGeometryShader,
6779 IWineD3DDeviceImpl_CreatePixelShader,
6780 IWineD3DDeviceImpl_CreatePalette,
6781 /*** Odd functions **/
6782 IWineD3DDeviceImpl_Init3D,
6783 IWineD3DDeviceImpl_InitGDI,
6784 IWineD3DDeviceImpl_Uninit3D,
6785 IWineD3DDeviceImpl_UninitGDI,
6786 IWineD3DDeviceImpl_SetMultithreaded,
6787 IWineD3DDeviceImpl_EvictManagedResources,
6788 IWineD3DDeviceImpl_GetAvailableTextureMem,
6789 IWineD3DDeviceImpl_GetBackBuffer,
6790 IWineD3DDeviceImpl_GetCreationParameters,
6791 IWineD3DDeviceImpl_GetDeviceCaps,
6792 IWineD3DDeviceImpl_GetDirect3D,
6793 IWineD3DDeviceImpl_GetDisplayMode,
6794 IWineD3DDeviceImpl_SetDisplayMode,
6795 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6796 IWineD3DDeviceImpl_GetRasterStatus,
6797 IWineD3DDeviceImpl_GetSwapChain,
6798 IWineD3DDeviceImpl_Reset,
6799 IWineD3DDeviceImpl_SetDialogBoxMode,
6800 IWineD3DDeviceImpl_SetCursorProperties,
6801 IWineD3DDeviceImpl_SetCursorPosition,
6802 IWineD3DDeviceImpl_ShowCursor,
6803 /*** Getters and setters **/
6804 IWineD3DDeviceImpl_SetClipPlane,
6805 IWineD3DDeviceImpl_GetClipPlane,
6806 IWineD3DDeviceImpl_SetClipStatus,
6807 IWineD3DDeviceImpl_GetClipStatus,
6808 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6809 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6810 IWineD3DDeviceImpl_SetDepthStencilSurface,
6811 IWineD3DDeviceImpl_GetDepthStencilSurface,
6812 IWineD3DDeviceImpl_SetGammaRamp,
6813 IWineD3DDeviceImpl_GetGammaRamp,
6814 IWineD3DDeviceImpl_SetIndexBuffer,
6815 IWineD3DDeviceImpl_GetIndexBuffer,
6816 IWineD3DDeviceImpl_SetBaseVertexIndex,
6817 IWineD3DDeviceImpl_GetBaseVertexIndex,
6818 IWineD3DDeviceImpl_SetLight,
6819 IWineD3DDeviceImpl_GetLight,
6820 IWineD3DDeviceImpl_SetLightEnable,
6821 IWineD3DDeviceImpl_GetLightEnable,
6822 IWineD3DDeviceImpl_SetMaterial,
6823 IWineD3DDeviceImpl_GetMaterial,
6824 IWineD3DDeviceImpl_SetNPatchMode,
6825 IWineD3DDeviceImpl_GetNPatchMode,
6826 IWineD3DDeviceImpl_SetPaletteEntries,
6827 IWineD3DDeviceImpl_GetPaletteEntries,
6828 IWineD3DDeviceImpl_SetPixelShader,
6829 IWineD3DDeviceImpl_GetPixelShader,
6830 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6831 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6832 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6833 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6834 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6835 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6836 IWineD3DDeviceImpl_SetRenderState,
6837 IWineD3DDeviceImpl_GetRenderState,
6838 IWineD3DDeviceImpl_SetRenderTarget,
6839 IWineD3DDeviceImpl_GetRenderTarget,
6840 IWineD3DDeviceImpl_SetSamplerState,
6841 IWineD3DDeviceImpl_GetSamplerState,
6842 IWineD3DDeviceImpl_SetScissorRect,
6843 IWineD3DDeviceImpl_GetScissorRect,
6844 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6845 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6846 IWineD3DDeviceImpl_SetStreamSource,
6847 IWineD3DDeviceImpl_GetStreamSource,
6848 IWineD3DDeviceImpl_SetStreamSourceFreq,
6849 IWineD3DDeviceImpl_GetStreamSourceFreq,
6850 IWineD3DDeviceImpl_SetTexture,
6851 IWineD3DDeviceImpl_GetTexture,
6852 IWineD3DDeviceImpl_SetTextureStageState,
6853 IWineD3DDeviceImpl_GetTextureStageState,
6854 IWineD3DDeviceImpl_SetTransform,
6855 IWineD3DDeviceImpl_GetTransform,
6856 IWineD3DDeviceImpl_SetVertexDeclaration,
6857 IWineD3DDeviceImpl_GetVertexDeclaration,
6858 IWineD3DDeviceImpl_SetVertexShader,
6859 IWineD3DDeviceImpl_GetVertexShader,
6860 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6861 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6862 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6863 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6864 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6865 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6866 IWineD3DDeviceImpl_SetViewport,
6867 IWineD3DDeviceImpl_GetViewport,
6868 IWineD3DDeviceImpl_MultiplyTransform,
6869 IWineD3DDeviceImpl_ValidateDevice,
6870 IWineD3DDeviceImpl_ProcessVertices,
6871 /*** State block ***/
6872 IWineD3DDeviceImpl_BeginStateBlock,
6873 IWineD3DDeviceImpl_EndStateBlock,
6874 /*** Scene management ***/
6875 IWineD3DDeviceImpl_BeginScene,
6876 IWineD3DDeviceImpl_EndScene,
6877 IWineD3DDeviceImpl_Present,
6878 IWineD3DDeviceImpl_Clear,
6879 IWineD3DDeviceImpl_ClearRendertargetView,
6880 /*** Drawing ***/
6881 IWineD3DDeviceImpl_SetPrimitiveType,
6882 IWineD3DDeviceImpl_GetPrimitiveType,
6883 IWineD3DDeviceImpl_DrawPrimitive,
6884 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6885 IWineD3DDeviceImpl_DrawPrimitiveUP,
6886 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6887 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6888 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6889 IWineD3DDeviceImpl_DrawRectPatch,
6890 IWineD3DDeviceImpl_DrawTriPatch,
6891 IWineD3DDeviceImpl_DeletePatch,
6892 IWineD3DDeviceImpl_ColorFill,
6893 IWineD3DDeviceImpl_UpdateTexture,
6894 IWineD3DDeviceImpl_UpdateSurface,
6895 IWineD3DDeviceImpl_GetFrontBufferData,
6896 /*** object tracking ***/
6897 IWineD3DDeviceImpl_EnumResources,
6898 IWineD3DDeviceImpl_GetSurfaceFromDC,
6899 IWineD3DDeviceImpl_AcquireFocusWindow,
6900 IWineD3DDeviceImpl_ReleaseFocusWindow,
6901 IWineD3DDeviceImpl_SetupFullscreenWindow,
6902 IWineD3DDeviceImpl_RestoreFullscreenWindow,
6905 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6906 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6907 IWineD3DDeviceParent *device_parent)
6909 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6910 const struct fragment_pipeline *fragment_pipeline;
6911 struct shader_caps shader_caps;
6912 struct fragment_caps ffp_caps;
6913 WINED3DDISPLAYMODE mode;
6914 unsigned int i;
6915 HRESULT hr;
6917 device->lpVtbl = &IWineD3DDevice_Vtbl;
6918 device->ref = 1;
6919 device->wined3d = (IWineD3D *)wined3d;
6920 IWineD3D_AddRef(device->wined3d);
6921 device->adapter = wined3d->adapter_count ? adapter : NULL;
6922 device->device_parent = device_parent;
6923 list_init(&device->resources);
6924 list_init(&device->shaders);
6926 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6928 /* Get the initial screen setup for ddraw. */
6929 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6930 if (FAILED(hr))
6932 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6933 IWineD3D_Release(device->wined3d);
6934 return hr;
6936 device->ddraw_width = mode.Width;
6937 device->ddraw_height = mode.Height;
6938 device->ddraw_format = mode.Format;
6940 /* Save the creation parameters. */
6941 device->createParms.AdapterOrdinal = adapter_idx;
6942 device->createParms.DeviceType = device_type;
6943 device->createParms.hFocusWindow = focus_window;
6944 device->createParms.BehaviorFlags = flags;
6946 device->devType = device_type;
6947 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6949 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6950 device->shader_backend = adapter->shader_backend;
6952 if (device->shader_backend)
6954 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6955 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6956 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6957 device->vs_clipping = shader_caps.VSClipping;
6959 fragment_pipeline = adapter->fragment_pipe;
6960 device->frag_pipe = fragment_pipeline;
6961 if (fragment_pipeline)
6963 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6964 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6966 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6967 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6968 if (FAILED(hr))
6970 ERR("Failed to compile state table, hr %#x.\n", hr);
6971 IWineD3D_Release(device->wined3d);
6972 return hr;
6975 device->blitter = adapter->blitter;
6977 return WINED3D_OK;
6981 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6982 DWORD rep = This->StateTable[state].representative;
6983 struct wined3d_context *context;
6984 DWORD idx;
6985 BYTE shift;
6986 UINT i;
6988 for(i = 0; i < This->numContexts; i++) {
6989 context = This->contexts[i];
6990 if(isStateDirty(context, rep)) continue;
6992 context->dirtyArray[context->numDirtyEntries++] = rep;
6993 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6994 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6995 context->isStateDirty[idx] |= (1 << shift);
6999 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7001 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7002 *width = context->current_rt->pow2Width;
7003 *height = context->current_rt->pow2Height;
7006 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7008 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7009 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7010 * current context's drawable, which is the size of the back buffer of the swapchain
7011 * the active context belongs to. */
7012 *width = swapchain->presentParms.BackBufferWidth;
7013 *height = swapchain->presentParms.BackBufferHeight;
7016 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window, BOOL unicode,
7017 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7019 if (device->filter_messages)
7021 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7022 window, message, wparam, lparam);
7023 if (unicode)
7024 return DefWindowProcW(window, message, wparam, lparam);
7025 else
7026 return DefWindowProcA(window, message, wparam, lparam);
7029 if (message == WM_DESTROY)
7031 TRACE("unregister window %p.\n", window);
7032 wined3d_unregister_window(window);
7034 if (device->focus_window == window) device->focus_window = NULL;
7035 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7038 if (unicode)
7039 return CallWindowProcW(proc, window, message, wparam, lparam);
7040 else
7041 return CallWindowProcA(proc, window, message, wparam, lparam);