wined3d: Pass a wined3d_state structure to use_ps().
[wine/multimedia.git] / dlls / wined3d / device.c
blobcf50ce8fad8f7530873c793fa4abe60b1741e2a5
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = This->stateBlock->state.vertex_declaration;
181 unsigned int i;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 struct wined3d_buffer *buffer = This->stateBlock->state.streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->state.streams[element->input_slot].stride;
207 if (This->stateBlock->state.user_stream)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
210 buffer_object = 0;
211 data = (BYTE *)buffer;
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((IWineD3DBuffer *)buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->state.load_base_vertex_index < 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This->stateBlock->state.load_base_vertex_index);
227 buffer_object = 0;
228 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->state.load_base_vertex_index * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 warned = TRUE;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
278 stride_used = FALSE;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
294 stream_info->elements[idx].format = element->format;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->state.user_stream)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
333 if (buffer->query)
334 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
340 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
342 e->format = wined3d_get_format(gl_info, strided->format);
343 e->stride = strided->dwStride;
344 e->data = strided->lpData;
345 e->stream_idx = 0;
346 e->buffer_object = 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
350 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
352 unsigned int i;
354 memset(stream_info, 0, sizeof(*stream_info));
356 if (strided->position.lpData)
357 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
358 if (strided->normal.lpData)
359 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
360 if (strided->diffuse.lpData)
361 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
362 if (strided->specular.lpData)
363 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
365 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
367 if (strided->texCoords[i].lpData)
368 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
369 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
372 stream_info->position_transformed = strided->position_transformed;
374 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
376 if (!stream_info->elements[i].format) continue;
378 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
379 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
381 stream_info->swizzle_map |= 1 << i;
383 stream_info->use_map |= 1 << i;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
410 struct wined3d_stream_info *stream_info = &device->strided_streams;
411 const struct wined3d_state *state = &device->stateBlock->state;
412 BOOL fixup = FALSE;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
421 else
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, !!state->vertex_shader, stream_info, &fixup);
427 if (state->vertex_shader && !stream_info->position_transformed)
429 if (state->vertex_declaration->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
434 else
436 device->useDrawStridedSlow = FALSE;
439 else
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
449 else
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = stateblock->state.textures[idx])) return;
462 srgb = stateblock->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 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
469 const struct wined3d_state *state = &stateblock->state;
470 unsigned int i;
472 if (use_vs(state))
474 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
476 if (state->vertex_shader->baseShader.reg_maps.sampler_type[i])
477 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
481 if (use_ps(state))
483 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
485 if (state->pixel_shader->baseShader.reg_maps.sampler_type[i])
486 device_preload_texture(stateblock, i);
489 else
491 WORD ffu_map = device->fixed_function_usage_map;
493 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
495 if (ffu_map & 1)
496 device_preload_texture(stateblock, i);
501 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
503 struct wined3d_context **new_array;
505 TRACE("Adding context %p.\n", context);
507 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
508 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
510 if (!new_array)
512 ERR("Failed to grow the context array.\n");
513 return FALSE;
516 new_array[device->numContexts++] = context;
517 device->contexts = new_array;
518 return TRUE;
521 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
523 struct wined3d_context **new_array;
524 BOOL found = FALSE;
525 UINT i;
527 TRACE("Removing context %p.\n", context);
529 for (i = 0; i < device->numContexts; ++i)
531 if (device->contexts[i] == context)
533 found = TRUE;
534 break;
538 if (!found)
540 ERR("Context %p doesn't exist in context array.\n", context);
541 return;
544 if (!--device->numContexts)
546 HeapFree(GetProcessHeap(), 0, device->contexts);
547 device->contexts = NULL;
548 return;
551 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
552 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
553 if (!new_array)
555 ERR("Failed to shrink context array. Oh well.\n");
556 return;
559 device->contexts = new_array;
562 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
564 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
565 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
567 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
569 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
571 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
575 /* Do not call while under the GL lock. */
576 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
577 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
579 if (device->onscreen_depth_stencil)
581 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
582 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
583 device->onscreen_depth_stencil->ds_current_size.cx,
584 device->onscreen_depth_stencil->ds_current_size.cy);
585 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
587 device->onscreen_depth_stencil = depth_stencil;
588 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
591 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
593 /* partial draw rect */
594 if (draw_rect->left || draw_rect->top
595 || draw_rect->right < target->currentDesc.Width
596 || draw_rect->bottom < target->currentDesc.Height)
597 return FALSE;
599 /* partial clear rect */
600 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
601 || clear_rect->right < target->currentDesc.Width
602 || clear_rect->bottom < target->currentDesc.Height))
603 return FALSE;
605 return TRUE;
608 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
609 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
611 RECT current_rect, r;
613 if (ds->Flags & location)
614 SetRect(&current_rect, 0, 0,
615 ds->ds_current_size.cx,
616 ds->ds_current_size.cy);
617 else
618 SetRectEmpty(&current_rect);
620 IntersectRect(&r, draw_rect, &current_rect);
621 if (EqualRect(&r, draw_rect))
623 /* current_rect ⊇ draw_rect, modify only. */
624 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
625 return;
628 if (EqualRect(&r, &current_rect))
630 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
632 if (!clear_rect)
634 /* Full clear, modify only. */
635 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
636 return;
639 IntersectRect(&r, draw_rect, clear_rect);
640 if (EqualRect(&r, draw_rect))
642 /* clear_rect ⊇ draw_rect, modify only. */
643 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
644 return;
648 /* Full load. */
649 surface_load_ds_location(ds, context, location);
650 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
653 /* Do not call while under the GL lock. */
654 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
655 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
656 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
658 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
659 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
660 IWineD3DSurfaceImpl *target = rts[0];
661 UINT drawable_width, drawable_height;
662 struct wined3d_context *context;
663 GLbitfield clear_mask = 0;
664 unsigned int i;
666 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
667 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
668 * for the cleared parts, and the untouched parts.
670 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
671 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
672 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
673 * checking all this if the dest surface is in the drawable anyway. */
674 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
676 for (i = 0; i < rt_count; ++i)
678 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
682 context = context_acquire(device, target);
683 if (!context->valid)
685 context_release(context);
686 WARN("Invalid context, skipping clear.\n");
687 return WINED3D_OK;
690 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
692 target->get_drawable_size(context, &drawable_width, &drawable_height);
694 ENTER_GL();
696 /* Only set the values up once, as they are not changing. */
697 if (flags & WINED3DCLEAR_STENCIL)
699 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
701 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
702 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
704 glStencilMask(~0U);
705 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
706 glClearStencil(stencil);
707 checkGLcall("glClearStencil");
708 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
711 if (flags & WINED3DCLEAR_ZBUFFER)
713 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
715 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
717 LEAVE_GL();
718 device_switch_onscreen_ds(device, context, depth_stencil);
719 ENTER_GL();
721 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
722 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
724 glDepthMask(GL_TRUE);
725 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 glClearDepth(depth);
727 checkGLcall("glClearDepth");
728 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
731 if (flags & WINED3DCLEAR_TARGET)
733 for (i = 0; i < rt_count; ++i)
735 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
738 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
743 glClearColor(color->r, color->g, color->b, color->a);
744 checkGLcall("glClearColor");
745 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
748 if (!clear_rect)
750 if (context->render_offscreen)
752 glScissor(draw_rect->left, draw_rect->top,
753 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
755 else
757 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
758 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
760 checkGLcall("glScissor");
761 glClear(clear_mask);
762 checkGLcall("glClear");
764 else
766 RECT current_rect;
768 /* Now process each rect in turn. */
769 for (i = 0; i < rect_count; ++i)
771 /* Note that GL uses lower left, width/height. */
772 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
774 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
775 wine_dbgstr_rect(&clear_rect[i]),
776 wine_dbgstr_rect(&current_rect));
778 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
779 * The rectangle is not cleared, no error is returned, but further rectanlges are
780 * still cleared if they are valid. */
781 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
783 TRACE("Rectangle with negative dimensions, ignoring.\n");
784 continue;
787 if (context->render_offscreen)
789 glScissor(current_rect.left, current_rect.top,
790 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
792 else
794 glScissor(current_rect.left, drawable_height - current_rect.bottom,
795 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
797 checkGLcall("glScissor");
799 glClear(clear_mask);
800 checkGLcall("glClear");
804 LEAVE_GL();
806 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
807 && target->container.u.swapchain->front_buffer == target))
808 wglFlush(); /* Flush to ensure ordering across contexts. */
810 context_release(context);
812 return WINED3D_OK;
816 /**********************************************************
817 * IUnknown parts follows
818 **********************************************************/
820 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
822 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
824 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
825 || IsEqualGUID(riid, &IID_IUnknown))
827 IUnknown_AddRef(iface);
828 *object = iface;
829 return S_OK;
832 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
834 *object = NULL;
835 return E_NOINTERFACE;
838 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
840 ULONG refCount = InterlockedIncrement(&This->ref);
842 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
843 return refCount;
846 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 ULONG refCount = InterlockedDecrement(&This->ref);
850 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
852 if (!refCount) {
853 UINT i;
855 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
856 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
857 This->multistate_funcs[i] = NULL;
860 /* TODO: Clean up all the surfaces and textures! */
861 /* NOTE: You must release the parent if the object was created via a callback
862 ** ***************************/
864 if (!list_empty(&This->resources))
866 IWineD3DResourceImpl *resource;
867 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
869 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
871 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
872 FIXME("Leftover resource %p with type %s (%#x).\n",
873 resource, debug_d3dresourcetype(type), type);
877 if(This->contexts) ERR("Context array not freed!\n");
878 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
879 This->haveHardwareCursor = FALSE;
881 IWineD3D_Release(This->wined3d);
882 This->wined3d = NULL;
883 HeapFree(GetProcessHeap(), 0, This);
884 TRACE("Freed device %p\n", This);
885 This = NULL;
887 return refCount;
890 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
891 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
894 struct wined3d_buffer *object;
895 HRESULT hr;
897 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
899 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
900 if (!object)
902 ERR("Failed to allocate memory\n");
903 return E_OUTOFMEMORY;
906 FIXME("Ignoring access flags (pool)\n");
908 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
909 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
910 if (FAILED(hr))
912 WARN("Failed to initialize buffer, hr %#x.\n", hr);
913 HeapFree(GetProcessHeap(), 0, object);
914 return hr;
916 object->desc = *desc;
918 TRACE("Created buffer %p.\n", object);
920 *buffer = (IWineD3DBuffer *)object;
922 return WINED3D_OK;
925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
926 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
927 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
930 struct wined3d_buffer *object;
931 HRESULT hr;
933 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
934 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
936 if (Pool == WINED3DPOOL_SCRATCH)
938 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
939 * anyway, SCRATCH vertex buffers aren't usable anywhere
941 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
942 *ppVertexBuffer = NULL;
943 return WINED3DERR_INVALIDCALL;
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
947 if (!object)
949 ERR("Out of memory\n");
950 *ppVertexBuffer = NULL;
951 return WINED3DERR_OUTOFVIDEOMEMORY;
954 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
955 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
956 if (FAILED(hr))
958 WARN("Failed to initialize buffer, hr %#x.\n", hr);
959 HeapFree(GetProcessHeap(), 0, object);
960 return hr;
963 TRACE("Created buffer %p.\n", object);
964 *ppVertexBuffer = (IWineD3DBuffer *)object;
966 return WINED3D_OK;
969 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
970 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
971 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
974 struct wined3d_buffer *object;
975 HRESULT hr;
977 TRACE("(%p) Creating index buffer\n", This);
979 /* Allocate the storage for the device */
980 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
981 if (!object)
983 ERR("Out of memory\n");
984 *ppIndexBuffer = NULL;
985 return WINED3DERR_OUTOFVIDEOMEMORY;
988 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
989 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
990 parent, parent_ops);
991 if (FAILED(hr))
993 WARN("Failed to initialize buffer, hr %#x\n", hr);
994 HeapFree(GetProcessHeap(), 0, object);
995 return hr;
998 TRACE("Created buffer %p.\n", object);
1000 *ppIndexBuffer = (IWineD3DBuffer *) object;
1002 return WINED3D_OK;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1006 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DStateBlockImpl *object;
1010 HRESULT hr;
1012 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1013 if(!object)
1015 ERR("Failed to allocate stateblock memory.\n");
1016 return E_OUTOFMEMORY;
1019 hr = stateblock_init(object, This, type);
1020 if (FAILED(hr))
1022 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1023 HeapFree(GetProcessHeap(), 0, object);
1024 return hr;
1027 TRACE("Created stateblock %p.\n", object);
1028 *stateblock = (IWineD3DStateBlock *)object;
1030 return WINED3D_OK;
1033 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1034 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1035 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1036 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1039 IWineD3DSurfaceImpl *object;
1040 HRESULT hr;
1042 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1043 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1044 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1045 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1046 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1048 if (Impl == SURFACE_OPENGL && !This->adapter)
1050 ERR("OpenGL surfaces are not available without OpenGL.\n");
1051 return WINED3DERR_NOTAVAILABLE;
1054 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1055 if (!object)
1057 ERR("Failed to allocate surface memory.\n");
1058 return WINED3DERR_OUTOFVIDEOMEMORY;
1061 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1062 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1063 if (FAILED(hr))
1065 WARN("Failed to initialize surface, returning %#x.\n", hr);
1066 HeapFree(GetProcessHeap(), 0, object);
1067 return hr;
1070 TRACE("(%p) : Created surface %p\n", This, object);
1072 *surface = (IWineD3DSurface *)object;
1074 return hr;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1078 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1080 struct wined3d_rendertarget_view *object;
1082 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1083 iface, resource, parent, rendertarget_view);
1085 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1086 if (!object)
1088 ERR("Failed to allocate memory\n");
1089 return E_OUTOFMEMORY;
1092 wined3d_rendertarget_view_init(object, resource, parent);
1094 TRACE("Created render target view %p.\n", object);
1095 *rendertarget_view = (IWineD3DRendertargetView *)object;
1097 return WINED3D_OK;
1100 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1101 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1102 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1105 IWineD3DTextureImpl *object;
1106 HRESULT hr;
1108 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1109 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1110 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1112 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1113 if (!object)
1115 ERR("Out of memory\n");
1116 *ppTexture = NULL;
1117 return WINED3DERR_OUTOFVIDEOMEMORY;
1120 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1121 if (FAILED(hr))
1123 WARN("Failed to initialize texture, returning %#x\n", hr);
1124 HeapFree(GetProcessHeap(), 0, object);
1125 *ppTexture = NULL;
1126 return hr;
1129 *ppTexture = (IWineD3DTexture *)object;
1131 TRACE("(%p) : Created texture %p\n", This, object);
1133 return WINED3D_OK;
1136 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1137 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1138 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1141 IWineD3DVolumeTextureImpl *object;
1142 HRESULT hr;
1144 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1145 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1147 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1148 if (!object)
1150 ERR("Out of memory\n");
1151 *ppVolumeTexture = NULL;
1152 return WINED3DERR_OUTOFVIDEOMEMORY;
1155 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1156 if (FAILED(hr))
1158 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1159 HeapFree(GetProcessHeap(), 0, object);
1160 *ppVolumeTexture = NULL;
1161 return hr;
1164 TRACE("(%p) : Created volume texture %p.\n", This, object);
1165 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1167 return WINED3D_OK;
1170 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1171 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1172 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1175 IWineD3DVolumeImpl *object;
1176 HRESULT hr;
1178 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1179 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1181 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1182 if (!object)
1184 ERR("Out of memory\n");
1185 *ppVolume = NULL;
1186 return WINED3DERR_OUTOFVIDEOMEMORY;
1189 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1190 if (FAILED(hr))
1192 WARN("Failed to initialize volume, returning %#x.\n", hr);
1193 HeapFree(GetProcessHeap(), 0, object);
1194 return hr;
1197 TRACE("(%p) : Created volume %p.\n", This, object);
1198 *ppVolume = (IWineD3DVolume *)object;
1200 return WINED3D_OK;
1203 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1204 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1205 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1208 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1209 HRESULT hr;
1211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1212 if (!object)
1214 ERR("Out of memory\n");
1215 *ppCubeTexture = NULL;
1216 return WINED3DERR_OUTOFVIDEOMEMORY;
1219 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1220 if (FAILED(hr))
1222 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1223 HeapFree(GetProcessHeap(), 0, object);
1224 *ppCubeTexture = NULL;
1225 return hr;
1228 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1229 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1231 return WINED3D_OK;
1234 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1235 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1238 IWineD3DQueryImpl *object;
1239 HRESULT hr;
1241 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1243 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1244 if (!object)
1246 ERR("Failed to allocate query memory.\n");
1247 return E_OUTOFMEMORY;
1250 hr = query_init(object, This, type);
1251 if (FAILED(hr))
1253 WARN("Failed to initialize query, hr %#x.\n", hr);
1254 HeapFree(GetProcessHeap(), 0, object);
1255 return hr;
1258 TRACE("Created query %p.\n", object);
1259 *query = (IWineD3DQuery *)object;
1261 return WINED3D_OK;
1264 /* Do not call while under the GL lock. */
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1266 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1267 void *parent, IWineD3DSwapChain **swapchain)
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 IWineD3DSwapChainImpl *object;
1271 HRESULT hr;
1273 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1274 iface, present_parameters, swapchain, parent, surface_type);
1276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1277 if (!object)
1279 ERR("Failed to allocate swapchain memory.\n");
1280 return E_OUTOFMEMORY;
1283 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1284 if (FAILED(hr))
1286 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1287 HeapFree(GetProcessHeap(), 0, object);
1288 return hr;
1291 TRACE("Created swapchain %p.\n", object);
1292 *swapchain = (IWineD3DSwapChain *)object;
1294 return WINED3D_OK;
1297 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1298 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1300 TRACE("(%p)\n", This);
1302 return This->NumberOfSwapChains;
1305 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1307 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1309 if(iSwapChain < This->NumberOfSwapChains) {
1310 *pSwapChain = This->swapchains[iSwapChain];
1311 IWineD3DSwapChain_AddRef(*pSwapChain);
1312 TRACE("(%p) returning %p\n", This, *pSwapChain);
1313 return WINED3D_OK;
1314 } else {
1315 TRACE("Swapchain out of range\n");
1316 *pSwapChain = NULL;
1317 return WINED3DERR_INVALIDCALL;
1321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1322 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1323 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 IWineD3DVertexDeclarationImpl *object = NULL;
1327 HRESULT hr;
1329 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1330 iface, declaration, parent, elements, element_count);
1332 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1333 if(!object)
1335 ERR("Failed to allocate vertex declaration memory.\n");
1336 return E_OUTOFMEMORY;
1339 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1340 if (FAILED(hr))
1342 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1343 HeapFree(GetProcessHeap(), 0, object);
1344 return hr;
1347 TRACE("Created vertex declaration %p.\n", object);
1348 *declaration = (IWineD3DVertexDeclaration *)object;
1350 return WINED3D_OK;
1353 struct wined3d_fvf_convert_state
1355 const struct wined3d_gl_info *gl_info;
1356 WINED3DVERTEXELEMENT *elements;
1357 UINT offset;
1358 UINT idx;
1361 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1362 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1364 WINED3DVERTEXELEMENT *elements = state->elements;
1365 const struct wined3d_format *format;
1366 UINT offset = state->offset;
1367 UINT idx = state->idx;
1369 elements[idx].format = format_id;
1370 elements[idx].input_slot = 0;
1371 elements[idx].offset = offset;
1372 elements[idx].output_slot = 0;
1373 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1374 elements[idx].usage = usage;
1375 elements[idx].usage_idx = usage_idx;
1377 format = wined3d_get_format(state->gl_info, format_id);
1378 state->offset += format->component_count * format->component_size;
1379 ++state->idx;
1382 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1383 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1385 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1386 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1387 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1388 BOOL has_blend_idx = has_blend &&
1389 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1390 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1391 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1392 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1393 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1394 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1395 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1397 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1398 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1399 struct wined3d_fvf_convert_state state;
1400 unsigned int size;
1401 unsigned int idx;
1402 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1403 if (has_blend_idx) num_blends--;
1405 /* Compute declaration size */
1406 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1407 has_psize + has_diffuse + has_specular + num_textures;
1409 state.gl_info = gl_info;
1410 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1411 if (!state.elements) return ~0U;
1412 state.offset = 0;
1413 state.idx = 0;
1415 if (has_pos)
1417 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1418 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1419 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1420 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1421 else
1422 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1425 if (has_blend && (num_blends > 0))
1427 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1428 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1429 else
1431 switch (num_blends)
1433 case 1:
1434 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1435 break;
1436 case 2:
1437 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1438 break;
1439 case 3:
1440 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1441 break;
1442 case 4:
1443 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1444 break;
1445 default:
1446 ERR("Unexpected amount of blend values: %u\n", num_blends);
1451 if (has_blend_idx)
1453 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1454 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1455 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1456 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1457 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1458 else
1459 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1463 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1464 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1465 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1467 for (idx = 0; idx < num_textures; ++idx)
1469 switch ((texcoords >> (idx * 2)) & 0x03)
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1473 break;
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1476 break;
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1479 break;
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1482 break;
1486 *ppVertexElements = state.elements;
1487 return size;
1490 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1491 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1492 IWineD3DVertexDeclaration **declaration)
1494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1495 WINED3DVERTEXELEMENT *elements;
1496 unsigned int size;
1497 DWORD hr;
1499 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1501 size = ConvertFvfToDeclaration(This, fvf, &elements);
1502 if (size == ~0U) return E_OUTOFMEMORY;
1504 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1505 HeapFree(GetProcessHeap(), 0, elements);
1506 return hr;
1509 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1510 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1511 void *parent, const struct wined3d_parent_ops *parent_ops,
1512 IWineD3DVertexShader **ppVertexShader)
1514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1515 IWineD3DVertexShaderImpl *object;
1516 HRESULT hr;
1518 if (This->vs_selected_mode == SHADER_NONE)
1519 return WINED3DERR_INVALIDCALL;
1521 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1522 if (!object)
1524 ERR("Failed to allocate shader memory.\n");
1525 return E_OUTOFMEMORY;
1528 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1529 if (FAILED(hr))
1531 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1532 HeapFree(GetProcessHeap(), 0, object);
1533 return hr;
1536 TRACE("Created vertex shader %p.\n", object);
1537 *ppVertexShader = (IWineD3DVertexShader *)object;
1539 return WINED3D_OK;
1542 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1543 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1544 void *parent, const struct wined3d_parent_ops *parent_ops,
1545 IWineD3DGeometryShader **shader)
1547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1548 struct wined3d_geometryshader *object;
1549 HRESULT hr;
1551 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1552 if (!object)
1554 ERR("Failed to allocate shader memory.\n");
1555 return E_OUTOFMEMORY;
1558 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1559 if (FAILED(hr))
1561 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1562 HeapFree(GetProcessHeap(), 0, object);
1563 return hr;
1566 TRACE("Created geometry shader %p.\n", object);
1567 *shader = (IWineD3DGeometryShader *)object;
1569 return WINED3D_OK;
1572 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1573 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1574 void *parent, const struct wined3d_parent_ops *parent_ops,
1575 IWineD3DPixelShader **ppPixelShader)
1577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1578 IWineD3DPixelShaderImpl *object;
1579 HRESULT hr;
1581 if (This->ps_selected_mode == SHADER_NONE)
1582 return WINED3DERR_INVALIDCALL;
1584 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1585 if (!object)
1587 ERR("Failed to allocate shader memory.\n");
1588 return E_OUTOFMEMORY;
1591 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1592 if (FAILED(hr))
1594 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1595 HeapFree(GetProcessHeap(), 0, object);
1596 return hr;
1599 TRACE("Created pixel shader %p.\n", object);
1600 *ppPixelShader = (IWineD3DPixelShader *)object;
1602 return WINED3D_OK;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1606 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1609 IWineD3DPaletteImpl *object;
1610 HRESULT hr;
1612 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1613 iface, Flags, PalEnt, Palette, parent);
1615 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1616 if (!object)
1618 ERR("Failed to allocate palette memory.\n");
1619 return E_OUTOFMEMORY;
1622 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1623 if (FAILED(hr))
1625 WARN("Failed to initialize palette, hr %#x.\n", hr);
1626 HeapFree(GetProcessHeap(), 0, object);
1627 return hr;
1630 TRACE("Created palette %p.\n", object);
1631 *Palette = (IWineD3DPalette *)object;
1633 return WINED3D_OK;
1636 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1637 HBITMAP hbm;
1638 BITMAP bm;
1639 HRESULT hr;
1640 HDC dcb = NULL, dcs = NULL;
1641 WINEDDCOLORKEY colorkey;
1643 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1644 if(hbm)
1646 GetObjectA(hbm, sizeof(BITMAP), &bm);
1647 dcb = CreateCompatibleDC(NULL);
1648 if(!dcb) goto out;
1649 SelectObject(dcb, hbm);
1651 else
1653 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1654 * couldn't be loaded
1656 memset(&bm, 0, sizeof(bm));
1657 bm.bmWidth = 32;
1658 bm.bmHeight = 32;
1661 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1662 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1663 &wined3d_null_parent_ops, &This->logo_surface);
1664 if (FAILED(hr))
1666 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1667 goto out;
1670 if(dcb) {
1671 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1672 if(FAILED(hr)) goto out;
1673 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1674 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1676 colorkey.dwColorSpaceLowValue = 0;
1677 colorkey.dwColorSpaceHighValue = 0;
1678 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1680 else
1682 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1683 /* Fill the surface with a white color to show that wined3d is there */
1684 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1687 out:
1688 if (dcb) DeleteDC(dcb);
1689 if (hbm) DeleteObject(hbm);
1692 /* Context activation is done by the caller. */
1693 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1695 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1696 unsigned int i;
1697 /* Under DirectX you can have texture stage operations even if no texture is
1698 bound, whereas opengl will only do texture operations when a valid texture is
1699 bound. We emulate this by creating dummy textures and binding them to each
1700 texture stage, but disable all stages by default. Hence if a stage is enabled
1701 then the default texture will kick in until replaced by a SetTexture call */
1702 ENTER_GL();
1704 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1706 /* The dummy texture does not have client storage backing */
1707 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1708 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1711 for (i = 0; i < gl_info->limits.textures; ++i)
1713 GLubyte white = 255;
1715 /* Make appropriate texture active */
1716 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1717 checkGLcall("glActiveTextureARB");
1719 /* Generate an opengl texture name */
1720 glGenTextures(1, &This->dummyTextureName[i]);
1721 checkGLcall("glGenTextures");
1722 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1724 /* Generate a dummy 2d texture (not using 1d because they cause many
1725 * DRI drivers fall back to sw) */
1726 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1727 checkGLcall("glBindTexture");
1729 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1730 checkGLcall("glTexImage2D");
1733 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1735 /* Reenable because if supported it is enabled by default */
1736 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1737 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1740 LEAVE_GL();
1743 /* Context activation is done by the caller. */
1744 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1746 ENTER_GL();
1747 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1748 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1749 LEAVE_GL();
1751 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1754 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1756 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1758 if (!wined3d_register_window(window, device))
1760 ERR("Failed to register window %p.\n", window);
1761 return E_FAIL;
1764 device->focus_window = window;
1765 SetForegroundWindow(window);
1767 return WINED3D_OK;
1770 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1772 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1774 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1775 device->focus_window = NULL;
1778 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1779 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1782 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1783 IWineD3DSwapChainImpl *swapchain = NULL;
1784 struct wined3d_context *context;
1785 HRESULT hr;
1786 DWORD state;
1787 unsigned int i;
1789 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1791 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1792 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1794 TRACE("(%p) : Creating stateblock\n", This);
1795 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1796 if (FAILED(hr))
1798 WARN("Failed to create stateblock\n");
1799 goto err_out;
1801 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1802 This->updateStateBlock = This->stateBlock;
1803 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1805 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1806 sizeof(*This->render_targets) * gl_info->limits.buffers);
1808 This->NumberOfPalettes = 1;
1809 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1810 if (!This->palettes || !This->render_targets)
1812 ERR("Out of memory!\n");
1813 hr = E_OUTOFMEMORY;
1814 goto err_out;
1816 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1817 if(!This->palettes[0]) {
1818 ERR("Out of memory!\n");
1819 hr = E_OUTOFMEMORY;
1820 goto err_out;
1822 for (i = 0; i < 256; ++i) {
1823 This->palettes[0][i].peRed = 0xFF;
1824 This->palettes[0][i].peGreen = 0xFF;
1825 This->palettes[0][i].peBlue = 0xFF;
1826 This->palettes[0][i].peFlags = 0xFF;
1828 This->currentPalette = 0;
1830 /* Initialize the texture unit mapping to a 1:1 mapping */
1831 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1833 if (state < gl_info->limits.fragment_samplers)
1835 This->texUnitMap[state] = state;
1836 This->rev_tex_unit_map[state] = state;
1837 } else {
1838 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1839 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1843 /* Setup the implicit swapchain. This also initializes a context. */
1844 TRACE("Creating implicit swapchain\n");
1845 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1846 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1847 if (FAILED(hr))
1849 WARN("Failed to create implicit swapchain\n");
1850 goto err_out;
1853 This->NumberOfSwapChains = 1;
1854 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1855 if(!This->swapchains) {
1856 ERR("Out of memory!\n");
1857 goto err_out;
1859 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1861 if (swapchain->back_buffers && swapchain->back_buffers[0])
1863 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1864 This->render_targets[0] = swapchain->back_buffers[0];
1866 else
1868 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1869 This->render_targets[0] = swapchain->front_buffer;
1871 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1873 /* Depth Stencil support */
1874 This->depth_stencil = This->auto_depth_stencil;
1875 if (This->depth_stencil)
1876 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1878 hr = This->shader_backend->shader_alloc_private(iface);
1879 if(FAILED(hr)) {
1880 TRACE("Shader private data couldn't be allocated\n");
1881 goto err_out;
1883 hr = This->frag_pipe->alloc_private(iface);
1884 if(FAILED(hr)) {
1885 TRACE("Fragment pipeline private data couldn't be allocated\n");
1886 goto err_out;
1888 hr = This->blitter->alloc_private(iface);
1889 if(FAILED(hr)) {
1890 TRACE("Blitter private data couldn't be allocated\n");
1891 goto err_out;
1894 /* Set up some starting GL setup */
1896 /* Setup all the devices defaults */
1897 stateblock_init_default_state(This->stateBlock);
1899 context = context_acquire(This, swapchain->front_buffer);
1901 create_dummy_textures(This);
1903 ENTER_GL();
1905 /* Initialize the current view state */
1906 This->view_ident = 1;
1907 This->contexts[0]->last_was_rhw = 0;
1908 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1909 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1911 switch(wined3d_settings.offscreen_rendering_mode) {
1912 case ORM_FBO:
1913 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1914 break;
1916 case ORM_BACKBUFFER:
1918 if (context_get_current()->aux_buffers > 0)
1920 TRACE("Using auxilliary buffer for offscreen rendering\n");
1921 This->offscreenBuffer = GL_AUX0;
1922 } else {
1923 TRACE("Using back buffer for offscreen rendering\n");
1924 This->offscreenBuffer = GL_BACK;
1929 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1930 LEAVE_GL();
1932 context_release(context);
1934 /* Clear the screen */
1935 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1936 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1937 0x00, 1.0f, 0);
1939 This->d3d_initialized = TRUE;
1941 if(wined3d_settings.logo) {
1942 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1944 This->highest_dirty_ps_const = 0;
1945 This->highest_dirty_vs_const = 0;
1946 return WINED3D_OK;
1948 err_out:
1949 HeapFree(GetProcessHeap(), 0, This->render_targets);
1950 HeapFree(GetProcessHeap(), 0, This->swapchains);
1951 This->NumberOfSwapChains = 0;
1952 if(This->palettes) {
1953 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1954 HeapFree(GetProcessHeap(), 0, This->palettes);
1956 This->NumberOfPalettes = 0;
1957 if(swapchain) {
1958 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1960 if(This->stateBlock) {
1961 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1962 This->stateBlock = NULL;
1964 if (This->blit_priv) {
1965 This->blitter->free_private(iface);
1967 if (This->fragment_priv) {
1968 This->frag_pipe->free_private(iface);
1970 if (This->shader_priv) {
1971 This->shader_backend->shader_free_private(iface);
1973 return hr;
1976 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1977 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1980 IWineD3DSwapChainImpl *swapchain = NULL;
1981 HRESULT hr;
1983 /* Setup the implicit swapchain */
1984 TRACE("Creating implicit swapchain\n");
1985 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1986 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1987 if (FAILED(hr))
1989 WARN("Failed to create implicit swapchain\n");
1990 goto err_out;
1993 This->NumberOfSwapChains = 1;
1994 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1995 if(!This->swapchains) {
1996 ERR("Out of memory!\n");
1997 goto err_out;
1999 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2000 return WINED3D_OK;
2002 err_out:
2003 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2004 return hr;
2007 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2009 IWineD3DResource_UnLoad(resource);
2010 IWineD3DResource_Release(resource);
2011 return WINED3D_OK;
2014 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2015 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2018 const struct wined3d_gl_info *gl_info;
2019 struct wined3d_context *context;
2020 int sampler;
2021 UINT i;
2022 TRACE("(%p)\n", This);
2024 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2026 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2027 * it was created. Thus make sure a context is active for the glDelete* calls
2029 context = context_acquire(This, NULL);
2030 gl_info = context->gl_info;
2032 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2034 /* Unload resources */
2035 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2037 TRACE("Deleting high order patches\n");
2038 for(i = 0; i < PATCHMAP_SIZE; i++) {
2039 struct list *e1, *e2;
2040 struct WineD3DRectPatch *patch;
2041 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2042 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2043 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2047 /* Delete the mouse cursor texture */
2048 if(This->cursorTexture) {
2049 ENTER_GL();
2050 glDeleteTextures(1, &This->cursorTexture);
2051 LEAVE_GL();
2052 This->cursorTexture = 0;
2055 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2056 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2058 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2059 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2062 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2063 * private data, it might contain opengl pointers
2065 if(This->depth_blt_texture) {
2066 ENTER_GL();
2067 glDeleteTextures(1, &This->depth_blt_texture);
2068 LEAVE_GL();
2069 This->depth_blt_texture = 0;
2071 if (This->depth_blt_rb) {
2072 ENTER_GL();
2073 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2074 LEAVE_GL();
2075 This->depth_blt_rb = 0;
2076 This->depth_blt_rb_w = 0;
2077 This->depth_blt_rb_h = 0;
2080 /* Release the update stateblock */
2081 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2082 if(This->updateStateBlock != This->stateBlock)
2083 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2085 This->updateStateBlock = NULL;
2087 { /* because were not doing proper internal refcounts releasing the primary state block
2088 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2089 to set this->stateBlock = NULL; first */
2090 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2091 This->stateBlock = NULL;
2093 /* Release the stateblock */
2094 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2095 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2099 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2100 This->blitter->free_private(iface);
2101 This->frag_pipe->free_private(iface);
2102 This->shader_backend->shader_free_private(iface);
2104 /* Release the buffers (with sanity checks)*/
2105 if (This->onscreen_depth_stencil)
2107 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2108 This->onscreen_depth_stencil = NULL;
2111 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2112 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2114 if (This->auto_depth_stencil != This->depth_stencil)
2115 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2117 This->depth_stencil = NULL;
2119 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2120 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2122 TRACE("Setting rendertarget to NULL\n");
2123 This->render_targets[0] = NULL;
2125 if (This->auto_depth_stencil)
2127 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2129 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2131 This->auto_depth_stencil = NULL;
2134 context_release(context);
2136 for(i=0; i < This->NumberOfSwapChains; i++) {
2137 TRACE("Releasing the implicit swapchain %d\n", i);
2138 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2139 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2143 HeapFree(GetProcessHeap(), 0, This->swapchains);
2144 This->swapchains = NULL;
2145 This->NumberOfSwapChains = 0;
2147 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2148 HeapFree(GetProcessHeap(), 0, This->palettes);
2149 This->palettes = NULL;
2150 This->NumberOfPalettes = 0;
2152 HeapFree(GetProcessHeap(), 0, This->render_targets);
2153 This->render_targets = NULL;
2155 This->d3d_initialized = FALSE;
2157 return WINED3D_OK;
2160 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2162 unsigned int i;
2164 for(i=0; i < This->NumberOfSwapChains; i++) {
2165 TRACE("Releasing the implicit swapchain %d\n", i);
2166 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2167 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2171 HeapFree(GetProcessHeap(), 0, This->swapchains);
2172 This->swapchains = NULL;
2173 This->NumberOfSwapChains = 0;
2174 return WINED3D_OK;
2177 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2178 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2179 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2181 * There is no way to deactivate thread safety once it is enabled.
2183 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2186 /*For now just store the flag(needed in case of ddraw) */
2187 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2190 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2191 const WINED3DDISPLAYMODE* pMode) {
2192 DEVMODEW devmode;
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2195 LONG ret;
2196 RECT clip_rc;
2198 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2200 /* Resize the screen even without a window:
2201 * The app could have unset it with SetCooperativeLevel, but not called
2202 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2203 * but we don't have any hwnd
2206 memset(&devmode, 0, sizeof(devmode));
2207 devmode.dmSize = sizeof(devmode);
2208 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2209 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2210 devmode.dmPelsWidth = pMode->Width;
2211 devmode.dmPelsHeight = pMode->Height;
2213 devmode.dmDisplayFrequency = pMode->RefreshRate;
2214 if (pMode->RefreshRate)
2215 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2217 /* Only change the mode if necessary */
2218 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2219 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2220 return WINED3D_OK;
2222 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2223 if (ret != DISP_CHANGE_SUCCESSFUL)
2225 if (devmode.dmDisplayFrequency)
2227 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2228 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2229 devmode.dmDisplayFrequency = 0;
2230 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2232 if(ret != DISP_CHANGE_SUCCESSFUL) {
2233 return WINED3DERR_NOTAVAILABLE;
2237 /* Store the new values */
2238 This->ddraw_width = pMode->Width;
2239 This->ddraw_height = pMode->Height;
2240 This->ddraw_format = pMode->Format;
2242 /* And finally clip mouse to our screen */
2243 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2244 ClipCursor(&clip_rc);
2246 return WINED3D_OK;
2249 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 *ppD3D = This->wined3d;
2252 TRACE("Returning %p.\n", *ppD3D);
2253 IWineD3D_AddRef(*ppD3D);
2254 return WINED3D_OK;
2257 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2261 (This->adapter->TextureRam/(1024*1024)),
2262 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2263 /* return simulated texture memory left */
2264 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2267 /*****
2268 * Get / Set Stream Source
2269 *****/
2270 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2271 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 struct wined3d_stream_state *stream;
2275 IWineD3DBuffer *oldSrc;
2277 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2278 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2280 if (StreamNumber >= MAX_STREAMS) {
2281 WARN("Stream out of range %d\n", StreamNumber);
2282 return WINED3DERR_INVALIDCALL;
2283 } else if(OffsetInBytes & 0x3) {
2284 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2285 return WINED3DERR_INVALIDCALL;
2288 stream = &This->updateStateBlock->state.streams[StreamNumber];
2289 oldSrc = (IWineD3DBuffer *)stream->buffer;
2291 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2293 if (oldSrc == pStreamData
2294 && stream->stride == Stride
2295 && stream->offset == OffsetInBytes)
2297 TRACE("Application is setting the old values over, nothing to do\n");
2298 return WINED3D_OK;
2301 stream->buffer = (struct wined3d_buffer *)pStreamData;
2302 if (pStreamData)
2304 stream->stride = Stride;
2305 stream->offset = OffsetInBytes;
2308 /* Handle recording of state blocks */
2309 if (This->isRecordingState) {
2310 TRACE("Recording... not performing anything\n");
2311 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2312 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2313 return WINED3D_OK;
2316 if (pStreamData)
2318 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2319 IWineD3DBuffer_AddRef(pStreamData);
2321 if (oldSrc)
2323 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2324 IWineD3DBuffer_Release(oldSrc);
2327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2329 return WINED3D_OK;
2332 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2333 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 struct wined3d_stream_state *stream;
2338 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2339 iface, StreamNumber, pStream, pOffset, pStride);
2341 if (StreamNumber >= MAX_STREAMS)
2343 WARN("Stream out of range %d\n", StreamNumber);
2344 return WINED3DERR_INVALIDCALL;
2347 stream = &This->stateBlock->state.streams[StreamNumber];
2348 *pStream = (IWineD3DBuffer *)stream->buffer;
2349 *pStride = stream->stride;
2350 if (pOffset) *pOffset = stream->offset;
2352 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2354 return WINED3D_OK;
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2359 struct wined3d_stream_state *stream;
2360 UINT oldFlags, oldFreq;
2362 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2364 /* Verify input at least in d3d9 this is invalid. */
2365 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2367 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2368 return WINED3DERR_INVALIDCALL;
2370 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2372 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2373 return WINED3DERR_INVALIDCALL;
2375 if (!Divider)
2377 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2378 return WINED3DERR_INVALIDCALL;
2381 stream = &This->updateStateBlock->state.streams[StreamNumber];
2382 oldFlags = stream->flags;
2383 oldFreq = stream->frequency;
2385 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2386 stream->frequency = Divider & 0x7FFFFF;
2388 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2390 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2393 return WINED3D_OK;
2396 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398 struct wined3d_stream_state *stream;
2400 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2402 stream = &This->updateStateBlock->state.streams[StreamNumber];
2403 *Divider = stream->flags | stream->frequency;
2405 TRACE("Returning %#x.\n", *Divider);
2407 return WINED3D_OK;
2410 /*****
2411 * Get / Set & Multiply Transform
2412 *****/
2413 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2416 /* Most of this routine, comments included copied from ddraw tree initially: */
2417 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2419 /* Handle recording of state blocks */
2420 if (This->isRecordingState) {
2421 TRACE("Recording... not performing anything\n");
2422 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2423 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2424 return WINED3D_OK;
2428 * If the new matrix is the same as the current one,
2429 * we cut off any further processing. this seems to be a reasonable
2430 * optimization because as was noticed, some apps (warcraft3 for example)
2431 * tend towards setting the same matrix repeatedly for some reason.
2433 * From here on we assume that the new matrix is different, wherever it matters.
2435 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2437 TRACE("The app is setting the same matrix over again\n");
2438 return WINED3D_OK;
2440 else
2442 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2446 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2447 where ViewMat = Camera space, WorldMat = world space.
2449 In OpenGL, camera and world space is combined into GL_MODELVIEW
2450 matrix. The Projection matrix stay projection matrix.
2453 /* Capture the times we can just ignore the change for now */
2454 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2455 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2456 /* Handled by the state manager */
2459 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2462 return WINED3D_OK;
2466 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2467 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2469 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2471 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2473 *matrix = device->stateBlock->state.transforms[state];
2475 return WINED3D_OK;
2478 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2479 const WINED3DMATRIX *mat = NULL;
2480 WINED3DMATRIX temp;
2482 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2483 * below means it will be recorded in a state block change, but it
2484 * works regardless where it is recorded.
2485 * If this is found to be wrong, change to StateBlock.
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2490 if (State <= HIGHEST_TRANSFORMSTATE)
2492 mat = &This->updateStateBlock->state.transforms[State];
2494 else
2496 FIXME("Unhandled transform state!!\n");
2499 multiply_matrix(&temp, mat, pMatrix);
2501 /* Apply change via set transform - will reapply to eg. lights this way */
2502 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2505 /*****
2506 * Get / Set Light
2507 *****/
2508 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2509 you can reference any indexes you want as long as that number max are enabled at any
2510 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2511 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2512 but when recording, just build a chain pretty much of commands to be replayed. */
2514 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2515 float rho;
2516 struct wined3d_light_info *object = NULL;
2517 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2518 struct list *e;
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2523 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2524 * the gl driver.
2526 if(!pLight) {
2527 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2528 return WINED3DERR_INVALIDCALL;
2531 switch(pLight->Type) {
2532 case WINED3DLIGHT_POINT:
2533 case WINED3DLIGHT_SPOT:
2534 case WINED3DLIGHT_PARALLELPOINT:
2535 case WINED3DLIGHT_GLSPOT:
2536 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2537 * most wanted
2539 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2541 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2542 return WINED3DERR_INVALIDCALL;
2544 break;
2546 case WINED3DLIGHT_DIRECTIONAL:
2547 /* Ignores attenuation */
2548 break;
2550 default:
2551 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2552 return WINED3DERR_INVALIDCALL;
2555 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2557 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2558 if(object->OriginalIndex == Index) break;
2559 object = NULL;
2562 if(!object) {
2563 TRACE("Adding new light\n");
2564 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2565 if(!object) {
2566 ERR("Out of memory error when allocating a light\n");
2567 return E_OUTOFMEMORY;
2569 list_add_head(&This->updateStateBlock->state.light_map[Hi], &object->entry);
2570 object->glIndex = -1;
2571 object->OriginalIndex = Index;
2574 /* Initialize the object */
2575 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,
2576 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2577 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2578 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2579 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2580 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2581 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2583 /* Save away the information */
2584 object->OriginalParms = *pLight;
2586 switch (pLight->Type) {
2587 case WINED3DLIGHT_POINT:
2588 /* Position */
2589 object->lightPosn[0] = pLight->Position.x;
2590 object->lightPosn[1] = pLight->Position.y;
2591 object->lightPosn[2] = pLight->Position.z;
2592 object->lightPosn[3] = 1.0f;
2593 object->cutoff = 180.0f;
2594 /* FIXME: Range */
2595 break;
2597 case WINED3DLIGHT_DIRECTIONAL:
2598 /* Direction */
2599 object->lightPosn[0] = -pLight->Direction.x;
2600 object->lightPosn[1] = -pLight->Direction.y;
2601 object->lightPosn[2] = -pLight->Direction.z;
2602 object->lightPosn[3] = 0.0f;
2603 object->exponent = 0.0f;
2604 object->cutoff = 180.0f;
2605 break;
2607 case WINED3DLIGHT_SPOT:
2608 /* Position */
2609 object->lightPosn[0] = pLight->Position.x;
2610 object->lightPosn[1] = pLight->Position.y;
2611 object->lightPosn[2] = pLight->Position.z;
2612 object->lightPosn[3] = 1.0f;
2614 /* Direction */
2615 object->lightDirn[0] = pLight->Direction.x;
2616 object->lightDirn[1] = pLight->Direction.y;
2617 object->lightDirn[2] = pLight->Direction.z;
2618 object->lightDirn[3] = 1.0f;
2621 * opengl-ish and d3d-ish spot lights use too different models for the
2622 * light "intensity" as a function of the angle towards the main light direction,
2623 * so we only can approximate very roughly.
2624 * however spot lights are rather rarely used in games (if ever used at all).
2625 * furthermore if still used, probably nobody pays attention to such details.
2627 if (!pLight->Falloff)
2629 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2630 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2631 * will always be 1.0 for both of them, and we don't have to care for the
2632 * rest of the rather complex calculation
2634 object->exponent = 0.0f;
2635 } else {
2636 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2637 if (rho < 0.0001f) rho = 0.0001f;
2638 object->exponent = -0.3f/logf(cosf(rho/2));
2640 if (object->exponent > 128.0f)
2642 object->exponent = 128.0f;
2644 object->cutoff = (float) (pLight->Phi*90/M_PI);
2646 /* FIXME: Range */
2647 break;
2649 default:
2650 FIXME("Unrecognized light type %d\n", pLight->Type);
2653 /* Update the live definitions if the light is currently assigned a glIndex */
2654 if (object->glIndex != -1 && !This->isRecordingState) {
2655 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2657 return WINED3D_OK;
2660 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2662 struct wined3d_light_info *lightInfo = NULL;
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2665 struct list *e;
2666 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2668 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2670 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2671 if(lightInfo->OriginalIndex == Index) break;
2672 lightInfo = NULL;
2675 if (!lightInfo)
2677 TRACE("Light information requested but light not defined\n");
2678 return WINED3DERR_INVALIDCALL;
2681 *pLight = lightInfo->OriginalParms;
2682 return WINED3D_OK;
2685 /*****
2686 * Get / Set Light Enable
2687 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2688 *****/
2689 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2691 struct wined3d_light_info *lightInfo = NULL;
2692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2694 struct list *e;
2695 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2697 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2699 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2700 if(lightInfo->OriginalIndex == Index) break;
2701 lightInfo = NULL;
2703 TRACE("Found light: %p\n", lightInfo);
2705 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2706 if (!lightInfo)
2708 TRACE("Light enabled requested but light not defined, so defining one!\n");
2709 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2711 /* Search for it again! Should be fairly quick as near head of list */
2712 LIST_FOR_EACH(e, &This->updateStateBlock->state.light_map[Hi])
2714 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2715 if(lightInfo->OriginalIndex == Index) break;
2716 lightInfo = NULL;
2718 if (!lightInfo)
2720 FIXME("Adding default lights has failed dismally\n");
2721 return WINED3DERR_INVALIDCALL;
2725 if(!Enable) {
2726 if(lightInfo->glIndex != -1) {
2727 if(!This->isRecordingState) {
2728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2731 This->updateStateBlock->state.lights[lightInfo->glIndex] = NULL;
2732 lightInfo->glIndex = -1;
2733 } else {
2734 TRACE("Light already disabled, nothing to do\n");
2736 lightInfo->enabled = FALSE;
2737 } else {
2738 lightInfo->enabled = TRUE;
2739 if (lightInfo->glIndex != -1) {
2740 /* nop */
2741 TRACE("Nothing to do as light was enabled\n");
2742 } else {
2743 int i;
2744 /* Find a free gl light */
2745 for (i = 0; i < This->maxConcurrentLights; ++i)
2747 if (!This->updateStateBlock->state.lights[i])
2749 This->updateStateBlock->state.lights[i] = lightInfo;
2750 lightInfo->glIndex = i;
2751 break;
2754 if(lightInfo->glIndex == -1) {
2755 /* Our tests show that Windows returns D3D_OK in this situation, even with
2756 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2757 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2758 * as well for those lights.
2760 * TODO: Test how this affects rendering
2762 WARN("Too many concurrently active lights\n");
2763 return WINED3D_OK;
2766 /* i == lightInfo->glIndex */
2767 if(!This->isRecordingState) {
2768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2778 struct wined3d_light_info *lightInfo = NULL;
2779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 struct list *e;
2781 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2782 TRACE("(%p) : for idx(%d)\n", This, Index);
2784 LIST_FOR_EACH(e, &This->stateBlock->state.light_map[Hi])
2786 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2787 if(lightInfo->OriginalIndex == Index) break;
2788 lightInfo = NULL;
2791 if (!lightInfo)
2793 TRACE("Light enabled state requested but light not defined\n");
2794 return WINED3DERR_INVALIDCALL;
2796 /* true is 128 according to SetLightEnable */
2797 *pEnable = lightInfo->enabled ? 128 : 0;
2798 return WINED3D_OK;
2801 /*****
2802 * Get / Set Clip Planes
2803 *****/
2804 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2808 /* Validate Index */
2809 if (Index >= This->adapter->gl_info.limits.clipplanes)
2811 TRACE("Application has requested clipplane this device doesn't support\n");
2812 return WINED3DERR_INVALIDCALL;
2815 This->updateStateBlock->changed.clipplane |= 1 << Index;
2817 if (This->updateStateBlock->state.clip_planes[Index][0] == pPlane[0]
2818 && This->updateStateBlock->state.clip_planes[Index][1] == pPlane[1]
2819 && This->updateStateBlock->state.clip_planes[Index][2] == pPlane[2]
2820 && This->updateStateBlock->state.clip_planes[Index][3] == pPlane[3])
2822 TRACE("Application is setting old values over, nothing to do\n");
2823 return WINED3D_OK;
2826 This->updateStateBlock->state.clip_planes[Index][0] = pPlane[0];
2827 This->updateStateBlock->state.clip_planes[Index][1] = pPlane[1];
2828 This->updateStateBlock->state.clip_planes[Index][2] = pPlane[2];
2829 This->updateStateBlock->state.clip_planes[Index][3] = pPlane[3];
2831 /* Handle recording of state blocks */
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2839 return WINED3D_OK;
2842 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844 TRACE("(%p) : for idx %d\n", This, Index);
2846 /* Validate Index */
2847 if (Index >= This->adapter->gl_info.limits.clipplanes)
2849 TRACE("Application has requested clipplane this device doesn't support\n");
2850 return WINED3DERR_INVALIDCALL;
2853 pPlane[0] = (float)This->stateBlock->state.clip_planes[Index][0];
2854 pPlane[1] = (float)This->stateBlock->state.clip_planes[Index][1];
2855 pPlane[2] = (float)This->stateBlock->state.clip_planes[Index][2];
2856 pPlane[3] = (float)This->stateBlock->state.clip_planes[Index][3];
2857 return WINED3D_OK;
2860 /*****
2861 * Get / Set Clip Plane Status
2862 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2863 *****/
2864 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 FIXME("(%p) : stub\n", This);
2868 if (!pClipStatus)
2869 return WINED3DERR_INVALIDCALL;
2871 This->updateStateBlock->state.clip_status.ClipUnion = pClipStatus->ClipUnion;
2872 This->updateStateBlock->state.clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2873 return WINED3D_OK;
2876 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 FIXME("(%p) : stub\n", This);
2880 if (!pClipStatus)
2881 return WINED3DERR_INVALIDCALL;
2883 pClipStatus->ClipUnion = This->updateStateBlock->state.clip_status.ClipUnion;
2884 pClipStatus->ClipIntersection = This->updateStateBlock->state.clip_status.ClipIntersection;
2885 return WINED3D_OK;
2888 /*****
2889 * Get / Set Material
2890 *****/
2891 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2894 This->updateStateBlock->changed.material = TRUE;
2895 This->updateStateBlock->state.material = *pMaterial;
2897 /* Handle recording of state blocks */
2898 if (This->isRecordingState) {
2899 TRACE("Recording... not performing anything\n");
2900 return WINED3D_OK;
2903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 *pMaterial = This->updateStateBlock->state.material;
2910 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2911 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2912 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2913 pMaterial->Ambient.b, pMaterial->Ambient.a);
2914 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2915 pMaterial->Specular.b, pMaterial->Specular.a);
2916 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2917 pMaterial->Emissive.b, pMaterial->Emissive.a);
2918 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2920 return WINED3D_OK;
2923 /*****
2924 * Get / Set Indices
2925 *****/
2926 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2927 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 IWineD3DBuffer *oldIdxs;
2932 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2933 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2935 This->updateStateBlock->changed.indices = TRUE;
2936 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2937 This->updateStateBlock->state.index_format = fmt;
2939 /* Handle recording of state blocks */
2940 if (This->isRecordingState) {
2941 TRACE("Recording... not performing anything\n");
2942 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2943 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2944 return WINED3D_OK;
2947 if(oldIdxs != pIndexData) {
2948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2949 if(pIndexData) {
2950 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2951 IWineD3DBuffer_AddRef(pIndexData);
2953 if(oldIdxs) {
2954 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2955 IWineD3DBuffer_Release(oldIdxs);
2959 return WINED3D_OK;
2962 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2968 /* up ref count on ppindexdata */
2969 if (*ppIndexData) {
2970 IWineD3DBuffer_AddRef(*ppIndexData);
2971 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2972 }else{
2973 TRACE("(%p) No index data set\n", This);
2975 TRACE("Returning %p\n", *ppIndexData);
2977 return WINED3D_OK;
2980 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2981 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 TRACE("(%p)->(%d)\n", This, BaseIndex);
2985 if (This->updateStateBlock->state.base_vertex_index == BaseIndex)
2987 TRACE("Application is setting the old value over, nothing to do\n");
2988 return WINED3D_OK;
2991 This->updateStateBlock->state.base_vertex_index = BaseIndex;
2993 if (This->isRecordingState) {
2994 TRACE("Recording... not performing anything\n");
2995 return WINED3D_OK;
2997 /* The base vertex index affects the stream sources */
2998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2999 return WINED3D_OK;
3002 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : base_index %p\n", This, base_index);
3006 *base_index = This->stateBlock->state.base_vertex_index;
3008 TRACE("Returning %u\n", *base_index);
3010 return WINED3D_OK;
3013 /*****
3014 * Get / Set Viewports
3015 *****/
3016 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 TRACE("(%p)\n", This);
3020 This->updateStateBlock->changed.viewport = TRUE;
3021 This->updateStateBlock->state.viewport = *pViewport;
3023 /* Handle recording of state blocks */
3024 if (This->isRecordingState) {
3025 TRACE("Recording... not performing anything\n");
3026 return WINED3D_OK;
3029 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3030 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3033 return WINED3D_OK;
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 TRACE("(%p)\n", This);
3040 *pViewport = This->stateBlock->state.viewport;
3041 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3045 WINED3DRENDERSTATETYPE State, DWORD Value)
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3048 DWORD oldValue = This->stateBlock->state.render_states[State];
3050 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3052 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3053 This->updateStateBlock->state.render_states[State] = Value;
3055 /* Handle recording of state blocks */
3056 if (This->isRecordingState) {
3057 TRACE("Recording... not performing anything\n");
3058 return WINED3D_OK;
3061 /* Compared here and not before the assignment to allow proper stateblock recording */
3062 if(Value == oldValue) {
3063 TRACE("Application is setting the old value over, nothing to do\n");
3064 } else {
3065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3068 return WINED3D_OK;
3071 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3072 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3078 *pValue = This->stateBlock->state.render_states[State];
3079 return WINED3D_OK;
3082 /*****
3083 * Get / Set Sampler States
3084 * TODO: Verify against dx9 definitions
3085 *****/
3087 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 DWORD oldValue;
3091 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3092 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3094 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3095 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3098 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3100 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3101 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3104 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3105 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3106 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3108 /* Handle recording of state blocks */
3109 if (This->isRecordingState) {
3110 TRACE("Recording... not performing anything\n");
3111 return WINED3D_OK;
3114 if(oldValue == Value) {
3115 TRACE("Application is setting the old value over, nothing to do\n");
3116 return WINED3D_OK;
3119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3121 return WINED3D_OK;
3124 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3128 This, Sampler, debug_d3dsamplerstate(Type), Type);
3130 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3131 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3134 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3136 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3137 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3139 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3140 TRACE("(%p) : Returning %#x\n", This, *Value);
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 This->updateStateBlock->changed.scissorRect = TRUE;
3149 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3151 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3152 return WINED3D_OK;
3154 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3156 if(This->isRecordingState) {
3157 TRACE("Recording... not performing anything\n");
3158 return WINED3D_OK;
3161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3163 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 *pRect = This->updateStateBlock->state.scissor_rect;
3170 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3171 return WINED3D_OK;
3174 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3176 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3178 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3180 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3181 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3183 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3184 This->updateStateBlock->changed.vertexDecl = TRUE;
3186 if (This->isRecordingState) {
3187 TRACE("Recording... not performing anything\n");
3188 return WINED3D_OK;
3189 } else if(pDecl == oldDecl) {
3190 /* Checked after the assignment to allow proper stateblock recording */
3191 TRACE("Application is setting the old declaration over, nothing to do\n");
3192 return WINED3D_OK;
3195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3196 return WINED3D_OK;
3199 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3204 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3205 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3206 return WINED3D_OK;
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3214 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3215 This->updateStateBlock->changed.vertexShader = TRUE;
3217 if (This->isRecordingState) {
3218 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3219 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3220 TRACE("Recording... not performing anything\n");
3221 return WINED3D_OK;
3222 } else if(oldShader == pShader) {
3223 /* Checked here to allow proper stateblock recording */
3224 TRACE("App is setting the old shader over, nothing to do\n");
3225 return WINED3D_OK;
3228 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3229 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3230 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3234 return WINED3D_OK;
3237 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3239 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3240 IWineD3DVertexShader *shader;
3242 TRACE("iface %p.\n", iface);
3244 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3245 if (shader) IWineD3DVertexShader_AddRef(shader);
3247 TRACE("Returning %p.\n", shader);
3248 return shader;
3251 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3252 IWineD3DDevice *iface,
3253 UINT start,
3254 CONST BOOL *srcData,
3255 UINT count) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3260 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3261 iface, srcData, start, count);
3263 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3265 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3266 for (i = 0; i < cnt; i++)
3267 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3269 for (i = start; i < cnt + start; ++i) {
3270 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3273 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3275 return WINED3D_OK;
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3279 IWineD3DDevice *iface,
3280 UINT start,
3281 BOOL *dstData,
3282 UINT count) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3285 int cnt = min(count, MAX_CONST_B - start);
3287 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3288 iface, dstData, start, count);
3290 if (!dstData || cnt < 0)
3291 return WINED3DERR_INVALIDCALL;
3293 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3298 IWineD3DDevice *iface,
3299 UINT start,
3300 CONST int *srcData,
3301 UINT count) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3306 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3307 iface, srcData, start, count);
3309 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3311 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3312 for (i = 0; i < cnt; i++)
3313 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3314 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3316 for (i = start; i < cnt + start; ++i) {
3317 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3320 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3322 return WINED3D_OK;
3325 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3326 IWineD3DDevice *iface,
3327 UINT start,
3328 int *dstData,
3329 UINT count) {
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3332 int cnt = min(count, MAX_CONST_I - start);
3334 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3335 iface, dstData, start, count);
3337 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3338 return WINED3DERR_INVALIDCALL;
3340 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3341 return WINED3D_OK;
3344 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3345 IWineD3DDevice *iface,
3346 UINT start,
3347 CONST float *srcData,
3348 UINT count) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3351 UINT i;
3353 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3354 iface, srcData, start, count);
3356 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3357 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3358 return WINED3DERR_INVALIDCALL;
3360 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3361 if(TRACE_ON(d3d)) {
3362 for (i = 0; i < count; i++)
3363 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3364 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3367 if (!This->isRecordingState)
3369 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3373 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3374 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3380 IWineD3DDevice *iface,
3381 UINT start,
3382 float *dstData,
3383 UINT count) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int cnt = min(count, This->d3d_vshader_constantF - start);
3388 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3389 iface, dstData, start, count);
3391 if (!dstData || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3395 return WINED3D_OK;
3398 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3399 DWORD i;
3400 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3406 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3408 DWORD i = This->rev_tex_unit_map[unit];
3409 DWORD j = This->texUnitMap[stage];
3411 This->texUnitMap[stage] = unit;
3412 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3414 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3417 This->rev_tex_unit_map[unit] = stage;
3418 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3420 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3424 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3425 int i;
3427 This->fixed_function_usage_map = 0;
3428 for (i = 0; i < MAX_TEXTURES; ++i)
3430 const struct wined3d_state *state = &This->stateBlock->state;
3431 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3432 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3433 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3434 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3435 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3436 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3437 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3438 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3440 if (color_op == WINED3DTOP_DISABLE) {
3441 /* Not used, and disable higher stages */
3442 break;
3445 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3446 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3447 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3448 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3449 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3450 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3451 This->fixed_function_usage_map |= (1 << i);
3454 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3455 This->fixed_function_usage_map |= (1 << (i + 1));
3460 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3462 unsigned int i, tex;
3463 WORD ffu_map;
3465 device_update_fixed_function_usage_map(This);
3466 ffu_map = This->fixed_function_usage_map;
3468 if (This->max_ffp_textures == gl_info->limits.texture_stages
3469 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3471 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3473 if (!(ffu_map & 1)) continue;
3475 if (This->texUnitMap[i] != i) {
3476 device_map_stage(This, i, i);
3477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3478 markTextureStagesDirty(This, i);
3481 return;
3484 /* Now work out the mapping */
3485 tex = 0;
3486 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3488 if (!(ffu_map & 1)) continue;
3490 if (This->texUnitMap[i] != tex) {
3491 device_map_stage(This, i, tex);
3492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3493 markTextureStagesDirty(This, i);
3496 ++tex;
3500 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3502 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3503 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3504 unsigned int i;
3506 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3507 if (sampler_type[i] && This->texUnitMap[i] != i)
3509 device_map_stage(This, i, i);
3510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3511 if (i < gl_info->limits.texture_stages)
3513 markTextureStagesDirty(This, i);
3519 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3520 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3522 DWORD current_mapping = This->rev_tex_unit_map[unit];
3524 /* Not currently used */
3525 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3527 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3528 /* Used by a fragment sampler */
3530 if (!pshader_sampler_tokens) {
3531 /* No pixel shader, check fixed function */
3532 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3535 /* Pixel shader, check the shader's sampler map */
3536 return !pshader_sampler_tokens[current_mapping];
3539 /* Used by a vertex sampler */
3540 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3543 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3545 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3546 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3547 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3548 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3549 int i;
3551 if (ps)
3553 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3555 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3556 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3557 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3560 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3561 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3562 if (vshader_sampler_type[i])
3564 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3566 /* Already mapped somewhere */
3567 continue;
3570 while (start >= 0) {
3571 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3573 device_map_stage(This, vsampler_idx, start);
3574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3576 --start;
3577 break;
3580 --start;
3586 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3588 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3589 const struct wined3d_state *state = &This->stateBlock->state;
3590 BOOL vs = use_vs(state);
3591 BOOL ps = use_ps(state);
3593 * Rules are:
3594 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3595 * that would be really messy and require shader recompilation
3596 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3597 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3599 if (ps) device_map_psamplers(This, gl_info);
3600 else device_map_fixed_function_samplers(This, gl_info);
3602 if (vs) device_map_vsamplers(This, ps, gl_info);
3605 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3609 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3610 This->updateStateBlock->changed.pixelShader = TRUE;
3612 /* Handle recording of state blocks */
3613 if (This->isRecordingState) {
3614 TRACE("Recording... not performing anything\n");
3617 if (This->isRecordingState) {
3618 TRACE("Recording... not performing anything\n");
3619 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3620 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3621 return WINED3D_OK;
3624 if(pShader == oldShader) {
3625 TRACE("App is setting the old pixel shader over, nothing to do\n");
3626 return WINED3D_OK;
3629 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3630 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3632 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3635 return WINED3D_OK;
3638 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3640 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3641 IWineD3DPixelShader *shader;
3643 TRACE("iface %p.\n", iface);
3645 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3646 if (shader) IWineD3DPixelShader_AddRef(shader);
3648 TRACE("Returning %p.\n", shader);
3649 return shader;
3652 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3653 IWineD3DDevice *iface,
3654 UINT start,
3655 CONST BOOL *srcData,
3656 UINT count) {
3658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3659 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3661 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3662 iface, srcData, start, count);
3664 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3666 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3667 for (i = 0; i < cnt; i++)
3668 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3670 for (i = start; i < cnt + start; ++i) {
3671 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3674 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3676 return WINED3D_OK;
3679 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3680 IWineD3DDevice *iface,
3681 UINT start,
3682 BOOL *dstData,
3683 UINT count) {
3685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3686 int cnt = min(count, MAX_CONST_B - start);
3688 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3689 iface, dstData, start, count);
3691 if (!dstData || cnt < 0)
3692 return WINED3DERR_INVALIDCALL;
3694 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3695 return WINED3D_OK;
3698 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3699 IWineD3DDevice *iface,
3700 UINT start,
3701 CONST int *srcData,
3702 UINT count) {
3704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3705 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3707 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3708 iface, srcData, start, count);
3710 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3712 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3713 for (i = 0; i < cnt; i++)
3714 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3715 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3717 for (i = start; i < cnt + start; ++i) {
3718 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3721 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3723 return WINED3D_OK;
3726 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3727 IWineD3DDevice *iface,
3728 UINT start,
3729 int *dstData,
3730 UINT count) {
3732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3733 int cnt = min(count, MAX_CONST_I - start);
3735 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3736 iface, dstData, start, count);
3738 if (!dstData || cnt < 0)
3739 return WINED3DERR_INVALIDCALL;
3741 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3742 return WINED3D_OK;
3745 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3746 IWineD3DDevice *iface,
3747 UINT start,
3748 CONST float *srcData,
3749 UINT count) {
3751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3752 UINT i;
3754 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3755 iface, srcData, start, count);
3757 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3758 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3759 return WINED3DERR_INVALIDCALL;
3761 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3762 if(TRACE_ON(d3d)) {
3763 for (i = 0; i < count; i++)
3764 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3765 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3768 if (!This->isRecordingState)
3770 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3774 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3775 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3777 return WINED3D_OK;
3780 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3781 IWineD3DDevice *iface,
3782 UINT start,
3783 float *dstData,
3784 UINT count) {
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int cnt = min(count, This->d3d_pshader_constantF - start);
3789 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3790 iface, dstData, start, count);
3792 if (!dstData || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3796 return WINED3D_OK;
3799 /* Context activation is done by the caller. */
3800 /* Do not call while under the GL lock. */
3801 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3802 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3803 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3804 DWORD DestFVF)
3806 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3807 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3808 unsigned int i;
3809 WINED3DVIEWPORT vp;
3810 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3811 BOOL doClip;
3812 DWORD numTextures;
3814 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3816 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3819 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3821 ERR("Source has no position mask\n");
3822 return WINED3DERR_INVALIDCALL;
3825 if (!dest->resource.allocatedMemory)
3826 buffer_get_sysmem(dest, gl_info);
3828 /* Get a pointer into the destination vbo(create one if none exists) and
3829 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3831 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3833 dest->flags |= WINED3D_BUFFER_CREATEBO;
3834 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3837 if (dest->buffer_object)
3839 unsigned char extrabytes = 0;
3840 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3841 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3842 * this may write 4 extra bytes beyond the area that should be written
3844 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3845 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3846 if(!dest_conv_addr) {
3847 ERR("Out of memory\n");
3848 /* Continue without storing converted vertices */
3850 dest_conv = dest_conv_addr;
3853 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3855 static BOOL warned = FALSE;
3857 * The clipping code is not quite correct. Some things need
3858 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3859 * so disable clipping for now.
3860 * (The graphics in Half-Life are broken, and my processvertices
3861 * test crashes with IDirect3DDevice3)
3862 doClip = TRUE;
3864 doClip = FALSE;
3865 if(!warned) {
3866 warned = TRUE;
3867 FIXME("Clipping is broken and disabled for now\n");
3869 } else doClip = FALSE;
3870 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3872 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3873 WINED3DTS_VIEW,
3874 &view_mat);
3875 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3876 WINED3DTS_PROJECTION,
3877 &proj_mat);
3878 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3879 WINED3DTS_WORLDMATRIX(0),
3880 &world_mat);
3882 TRACE("View mat:\n");
3883 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);
3884 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);
3885 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);
3886 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);
3888 TRACE("Proj mat:\n");
3889 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);
3890 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);
3891 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);
3892 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);
3894 TRACE("World mat:\n");
3895 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);
3896 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);
3897 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);
3898 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);
3900 /* Get the viewport */
3901 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3902 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3903 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3905 multiply_matrix(&mat,&view_mat,&world_mat);
3906 multiply_matrix(&mat,&proj_mat,&mat);
3908 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3910 for (i = 0; i < dwCount; i+= 1) {
3911 unsigned int tex_index;
3913 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3914 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3915 /* The position first */
3916 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3917 const float *p = (const float *)(element->data + i * element->stride);
3918 float x, y, z, rhw;
3919 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3921 /* Multiplication with world, view and projection matrix */
3922 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);
3923 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);
3924 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);
3925 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);
3927 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3929 /* WARNING: The following things are taken from d3d7 and were not yet checked
3930 * against d3d8 or d3d9!
3933 /* Clipping conditions: From msdn
3935 * A vertex is clipped if it does not match the following requirements
3936 * -rhw < x <= rhw
3937 * -rhw < y <= rhw
3938 * 0 < z <= rhw
3939 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3941 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3942 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3946 if( !doClip ||
3947 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3948 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3949 ( rhw > eps ) ) ) {
3951 /* "Normal" viewport transformation (not clipped)
3952 * 1) The values are divided by rhw
3953 * 2) The y axis is negative, so multiply it with -1
3954 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3955 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3956 * 4) Multiply x with Width/2 and add Width/2
3957 * 5) The same for the height
3958 * 6) Add the viewpoint X and Y to the 2D coordinates and
3959 * The minimum Z value to z
3960 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3962 * Well, basically it's simply a linear transformation into viewport
3963 * coordinates
3966 x /= rhw;
3967 y /= rhw;
3968 z /= rhw;
3970 y *= -1;
3972 x *= vp.Width / 2;
3973 y *= vp.Height / 2;
3974 z *= vp.MaxZ - vp.MinZ;
3976 x += vp.Width / 2 + vp.X;
3977 y += vp.Height / 2 + vp.Y;
3978 z += vp.MinZ;
3980 rhw = 1 / rhw;
3981 } else {
3982 /* That vertex got clipped
3983 * Contrary to OpenGL it is not dropped completely, it just
3984 * undergoes a different calculation.
3986 TRACE("Vertex got clipped\n");
3987 x += rhw;
3988 y += rhw;
3990 x /= 2;
3991 y /= 2;
3993 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3994 * outside of the main vertex buffer memory. That needs some more
3995 * investigation...
3999 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4002 ( (float *) dest_ptr)[0] = x;
4003 ( (float *) dest_ptr)[1] = y;
4004 ( (float *) dest_ptr)[2] = z;
4005 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4007 dest_ptr += 3 * sizeof(float);
4009 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4010 dest_ptr += sizeof(float);
4013 if(dest_conv) {
4014 float w = 1 / rhw;
4015 ( (float *) dest_conv)[0] = x * w;
4016 ( (float *) dest_conv)[1] = y * w;
4017 ( (float *) dest_conv)[2] = z * w;
4018 ( (float *) dest_conv)[3] = w;
4020 dest_conv += 3 * sizeof(float);
4022 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4023 dest_conv += sizeof(float);
4027 if (DestFVF & WINED3DFVF_PSIZE) {
4028 dest_ptr += sizeof(DWORD);
4029 if(dest_conv) dest_conv += sizeof(DWORD);
4031 if (DestFVF & WINED3DFVF_NORMAL) {
4032 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4033 const float *normal = (const float *)(element->data + i * element->stride);
4034 /* AFAIK this should go into the lighting information */
4035 FIXME("Didn't expect the destination to have a normal\n");
4036 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4037 if(dest_conv) {
4038 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4042 if (DestFVF & WINED3DFVF_DIFFUSE) {
4043 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4044 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4045 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4047 static BOOL warned = FALSE;
4049 if(!warned) {
4050 ERR("No diffuse color in source, but destination has one\n");
4051 warned = TRUE;
4054 *( (DWORD *) dest_ptr) = 0xffffffff;
4055 dest_ptr += sizeof(DWORD);
4057 if(dest_conv) {
4058 *( (DWORD *) dest_conv) = 0xffffffff;
4059 dest_conv += sizeof(DWORD);
4062 else {
4063 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4064 if(dest_conv) {
4065 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4066 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4067 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4068 dest_conv += sizeof(DWORD);
4073 if (DestFVF & WINED3DFVF_SPECULAR)
4075 /* What's the color value in the feedback buffer? */
4076 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4077 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4078 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4080 static BOOL warned = FALSE;
4082 if(!warned) {
4083 ERR("No specular color in source, but destination has one\n");
4084 warned = TRUE;
4087 *( (DWORD *) dest_ptr) = 0xFF000000;
4088 dest_ptr += sizeof(DWORD);
4090 if(dest_conv) {
4091 *( (DWORD *) dest_conv) = 0xFF000000;
4092 dest_conv += sizeof(DWORD);
4095 else {
4096 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4097 if(dest_conv) {
4098 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4099 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4100 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4101 dest_conv += sizeof(DWORD);
4106 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4107 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4108 const float *tex_coord = (const float *)(element->data + i * element->stride);
4109 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4111 ERR("No source texture, but destination requests one\n");
4112 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4113 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4115 else {
4116 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4117 if(dest_conv) {
4118 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4124 if (dest_conv)
4126 ENTER_GL();
4128 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4129 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4130 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4131 dwCount * get_flexible_vertex_size(DestFVF),
4132 dest_conv_addr));
4133 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4135 LEAVE_GL();
4137 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4140 return WINED3D_OK;
4142 #undef copy_and_next
4144 /* Do not call while under the GL lock. */
4145 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4146 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4147 DWORD DestFVF)
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 struct wined3d_stream_info stream_info;
4151 const struct wined3d_gl_info *gl_info;
4152 struct wined3d_context *context;
4153 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4154 HRESULT hr;
4156 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4158 if(pVertexDecl) {
4159 ERR("Output vertex declaration not implemented yet\n");
4162 /* Need any context to write to the vbo. */
4163 context = context_acquire(This, NULL);
4164 gl_info = context->gl_info;
4166 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4167 * control the streamIsUP flag, thus restore it afterwards.
4169 This->stateBlock->state.user_stream = FALSE;
4170 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4171 This->stateBlock->state.user_stream = streamWasUP;
4173 if(vbo || SrcStartIndex) {
4174 unsigned int i;
4175 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4176 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4178 * Also get the start index in, but only loop over all elements if there's something to add at all.
4180 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4182 struct wined3d_stream_info_element *e;
4184 if (!(stream_info.use_map & (1 << i))) continue;
4186 e = &stream_info.elements[i];
4187 if (e->buffer_object)
4189 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4190 e->buffer_object = 0;
4191 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4192 ENTER_GL();
4193 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4194 vb->buffer_object = 0;
4195 LEAVE_GL();
4197 if (e->data) e->data += e->stride * SrcStartIndex;
4201 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4202 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4204 context_release(context);
4206 return hr;
4209 /*****
4210 * Get / Set Texture Stage States
4211 * TODO: Verify against dx9 definitions
4212 *****/
4213 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4216 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4217 DWORD oldValue;
4219 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4221 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4223 WARN("Invalid Type %d passed.\n", Type);
4224 return WINED3D_OK;
4227 if (Stage >= gl_info->limits.texture_stages)
4229 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4230 Stage, gl_info->limits.texture_stages - 1);
4231 return WINED3D_OK;
4234 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4235 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4236 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4238 if (This->isRecordingState) {
4239 TRACE("Recording... not performing anything\n");
4240 return WINED3D_OK;
4243 /* Checked after the assignments to allow proper stateblock recording */
4244 if(oldValue == Value) {
4245 TRACE("App is setting the old value over, nothing to do\n");
4246 return WINED3D_OK;
4249 if (Stage > This->stateBlock->state.lowest_disabled_stage
4250 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4251 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4253 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4254 * Changes in other states are important on disabled stages too
4256 return WINED3D_OK;
4259 if(Type == WINED3DTSS_COLOROP) {
4260 unsigned int i;
4262 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4263 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4264 * they have to be disabled
4266 * The current stage is dirtified below.
4268 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4270 TRACE("Additionally dirtifying stage %u\n", i);
4271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4273 This->stateBlock->state.lowest_disabled_stage = Stage;
4274 TRACE("New lowest disabled: %u\n", Stage);
4275 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4276 /* Previously disabled stage enabled. Stages above it may need enabling
4277 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4278 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4280 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4283 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4285 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4286 break;
4287 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4290 This->stateBlock->state.lowest_disabled_stage = i;
4291 TRACE("New lowest disabled: %u\n", i);
4295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4297 return WINED3D_OK;
4300 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304 TRACE("iface %p, stage %u, state %s, value %p.\n",
4305 iface, Stage, debug_d3dtexturestate(Type), pValue);
4307 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4309 WARN("Invalid Type %d passed.\n", Type);
4310 return WINED3D_OK;
4313 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4314 TRACE("Returning %#x.\n", *pValue);
4316 return WINED3D_OK;
4319 /*****
4320 * Get / Set Texture
4321 *****/
4322 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4323 DWORD stage, IWineD3DBaseTexture *texture)
4325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4326 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4327 IWineD3DBaseTexture *prev;
4329 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4331 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4332 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4334 /* Windows accepts overflowing this array... we do not. */
4335 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4337 WARN("Ignoring invalid stage %u.\n", stage);
4338 return WINED3D_OK;
4341 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4342 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4344 WARN("Rejecting attempt to set scratch texture.\n");
4345 return WINED3DERR_INVALIDCALL;
4348 This->updateStateBlock->changed.textures |= 1 << stage;
4350 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4351 TRACE("Previous texture %p.\n", prev);
4353 if (texture == prev)
4355 TRACE("App is setting the same texture again, nothing to do.\n");
4356 return WINED3D_OK;
4359 TRACE("Setting new texture to %p.\n", texture);
4360 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4362 if (This->isRecordingState)
4364 TRACE("Recording... not performing anything\n");
4366 if (texture) IWineD3DBaseTexture_AddRef(texture);
4367 if (prev) IWineD3DBaseTexture_Release(prev);
4369 return WINED3D_OK;
4372 if (texture)
4374 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4375 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4376 GLenum dimensions = t->baseTexture.target;
4378 IWineD3DBaseTexture_AddRef(texture);
4380 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4383 if (!prev && stage < gl_info->limits.texture_stages)
4385 /* The source arguments for color and alpha ops have different
4386 * meanings when a NULL texture is bound, so the COLOROP and
4387 * ALPHAOP have to be dirtified. */
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4392 if (bind_count == 1) t->baseTexture.sampler = stage;
4395 if (prev)
4397 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4398 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4400 IWineD3DBaseTexture_Release(prev);
4402 if (!texture && stage < gl_info->limits.texture_stages)
4404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4408 if (bind_count && t->baseTexture.sampler == stage)
4410 unsigned int i;
4412 /* Search for other stages the texture is bound to. Shouldn't
4413 * happen if applications bind textures to a single stage only. */
4414 TRACE("Searching for other stages the texture is bound to.\n");
4415 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4417 if (This->updateStateBlock->state.textures[i] == t)
4419 TRACE("Texture is also bound to stage %u.\n", i);
4420 t->baseTexture.sampler = i;
4421 break;
4427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4429 return WINED3D_OK;
4432 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4437 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4438 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4441 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4443 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4444 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4447 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4448 if (*ppTexture)
4449 IWineD3DBaseTexture_AddRef(*ppTexture);
4451 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4453 return WINED3D_OK;
4456 /*****
4457 * Get Back Buffer
4458 *****/
4459 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4460 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4462 IWineD3DSwapChain *swapchain;
4463 HRESULT hr;
4465 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4466 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4468 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4469 if (FAILED(hr))
4471 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4472 return hr;
4475 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4476 IWineD3DSwapChain_Release(swapchain);
4477 if (FAILED(hr))
4479 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4480 return hr;
4483 return WINED3D_OK;
4486 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4488 WARN("(%p) : stub, calling idirect3d for now\n", This);
4489 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4492 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4494 IWineD3DSwapChain *swapChain;
4495 HRESULT hr;
4497 if(iSwapChain > 0) {
4498 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4499 if (hr == WINED3D_OK) {
4500 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4501 IWineD3DSwapChain_Release(swapChain);
4502 } else {
4503 FIXME("(%p) Error getting display mode\n", This);
4505 } else {
4506 /* Don't read the real display mode,
4507 but return the stored mode instead. X11 can't change the color
4508 depth, and some apps are pretty angry if they SetDisplayMode from
4509 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4511 Also don't relay to the swapchain because with ddraw it's possible
4512 that there isn't a swapchain at all */
4513 pMode->Width = This->ddraw_width;
4514 pMode->Height = This->ddraw_height;
4515 pMode->Format = This->ddraw_format;
4516 pMode->RefreshRate = 0;
4517 hr = WINED3D_OK;
4520 return hr;
4523 /*****
4524 * Stateblock related functions
4525 *****/
4527 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DStateBlock *stateblock;
4530 HRESULT hr;
4532 TRACE("(%p)\n", This);
4534 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4536 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4537 if (FAILED(hr)) return hr;
4539 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4540 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4541 This->isRecordingState = TRUE;
4543 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4545 return WINED3D_OK;
4548 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4550 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4552 if (!This->isRecordingState) {
4553 WARN("(%p) not recording! returning error\n", This);
4554 *ppStateBlock = NULL;
4555 return WINED3DERR_INVALIDCALL;
4558 stateblock_init_contained_states(object);
4560 *ppStateBlock = (IWineD3DStateBlock*) object;
4561 This->isRecordingState = FALSE;
4562 This->updateStateBlock = This->stateBlock;
4563 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4564 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4565 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4566 return WINED3D_OK;
4569 /*****
4570 * Scene related functions
4571 *****/
4572 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4573 /* At the moment we have no need for any functionality at the beginning
4574 of a scene */
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 TRACE("(%p)\n", This);
4578 if(This->inScene) {
4579 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4580 return WINED3DERR_INVALIDCALL;
4582 This->inScene = TRUE;
4583 return WINED3D_OK;
4586 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4589 struct wined3d_context *context;
4591 TRACE("(%p)\n", This);
4593 if(!This->inScene) {
4594 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4595 return WINED3DERR_INVALIDCALL;
4598 context = context_acquire(This, NULL);
4599 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4600 wglFlush();
4601 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4602 * fails. */
4603 context_release(context);
4605 This->inScene = FALSE;
4606 return WINED3D_OK;
4609 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4610 const RECT *pSourceRect, const RECT *pDestRect,
4611 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4613 IWineD3DSwapChain *swapChain = NULL;
4614 int i;
4615 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4617 TRACE("iface %p.\n", iface);
4619 for(i = 0 ; i < swapchains ; i ++) {
4621 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4622 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4623 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4624 IWineD3DSwapChain_Release(swapChain);
4627 return WINED3D_OK;
4630 /* Do not call while under the GL lock. */
4631 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4632 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4634 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4635 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4636 RECT draw_rect;
4638 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4639 iface, rect_count, rects, flags, color, depth, stencil);
4641 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4643 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4644 /* TODO: What about depth stencil buffers without stencil bits? */
4645 return WINED3DERR_INVALIDCALL;
4648 device_get_draw_rect(device, &draw_rect);
4650 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4651 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4654 /*****
4655 * Drawing functions
4656 *****/
4658 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4659 WINED3DPRIMITIVETYPE primitive_type)
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4665 This->updateStateBlock->changed.primitive_type = TRUE;
4666 This->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4669 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4670 WINED3DPRIMITIVETYPE *primitive_type)
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4674 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4676 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->state.gl_primitive_type);
4678 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4681 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4687 if (!This->stateBlock->state.vertex_declaration)
4689 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4690 return WINED3DERR_INVALIDCALL;
4693 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4694 if (This->stateBlock->state.user_stream)
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4697 This->stateBlock->state.user_stream = FALSE;
4700 if (This->stateBlock->state.load_base_vertex_index)
4702 This->stateBlock->state.load_base_vertex_index = 0;
4703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4705 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4706 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4707 return WINED3D_OK;
4710 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 struct wined3d_buffer *index_buffer;
4714 UINT idxStride = 2;
4715 GLuint vbo;
4717 index_buffer = This->stateBlock->state.index_buffer;
4718 if (!index_buffer)
4720 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4721 * without an index buffer set. (The first time at least...)
4722 * D3D8 simply dies, but I doubt it can do much harm to return
4723 * D3DERR_INVALIDCALL there as well. */
4724 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4725 return WINED3DERR_INVALIDCALL;
4728 if (!This->stateBlock->state.vertex_declaration)
4730 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4731 return WINED3DERR_INVALIDCALL;
4734 if (This->stateBlock->state.user_stream)
4736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4737 This->stateBlock->state.user_stream = FALSE;
4739 vbo = index_buffer->buffer_object;
4741 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4743 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4744 idxStride = 2;
4745 else
4746 idxStride = 4;
4748 if (This->stateBlock->state.load_base_vertex_index != This->stateBlock->state.base_vertex_index)
4750 This->stateBlock->state.load_base_vertex_index = This->stateBlock->state.base_vertex_index;
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4754 drawPrimitive(iface, index_count, startIndex, idxStride,
4755 vbo ? NULL : index_buffer->resource.allocatedMemory);
4757 return WINED3D_OK;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4761 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 struct wined3d_stream_state *stream;
4765 IWineD3DBuffer *vb;
4767 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4768 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4770 if (!This->stateBlock->state.vertex_declaration)
4772 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4773 return WINED3DERR_INVALIDCALL;
4776 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4777 stream = &This->stateBlock->state.streams[0];
4778 vb = (IWineD3DBuffer *)stream->buffer;
4779 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4780 if (vb) IWineD3DBuffer_Release(vb);
4781 stream->offset = 0;
4782 stream->stride = VertexStreamZeroStride;
4783 This->stateBlock->state.user_stream = TRUE;
4784 This->stateBlock->state.load_base_vertex_index = 0;
4786 /* TODO: Only mark dirty if drawing from a different UP address */
4787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4789 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4791 /* MSDN specifies stream zero settings must be set to NULL */
4792 stream->buffer = NULL;
4793 stream->stride = 0;
4795 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4796 * the new stream sources or use UP drawing again
4798 return WINED3D_OK;
4801 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4802 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4803 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4805 int idxStride;
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 struct wined3d_stream_state *stream;
4808 IWineD3DBuffer *vb;
4809 IWineD3DBuffer *ib;
4811 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4812 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4814 if (!This->stateBlock->state.vertex_declaration)
4816 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4817 return WINED3DERR_INVALIDCALL;
4820 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4821 idxStride = 2;
4822 } else {
4823 idxStride = 4;
4826 stream = &This->stateBlock->state.streams[0];
4827 vb = (IWineD3DBuffer *)stream->buffer;
4828 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4829 if (vb) IWineD3DBuffer_Release(vb);
4830 stream->offset = 0;
4831 stream->stride = VertexStreamZeroStride;
4832 This->stateBlock->state.user_stream = TRUE;
4834 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4835 This->stateBlock->state.base_vertex_index = 0;
4836 This->stateBlock->state.load_base_vertex_index = 0;
4837 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4841 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4843 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4844 stream->buffer = NULL;
4845 stream->stride = 0;
4846 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4847 if (ib)
4849 IWineD3DBuffer_Release(ib);
4850 This->stateBlock->state.index_buffer = NULL;
4852 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4853 * SetStreamSource to specify a vertex buffer
4856 return WINED3D_OK;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4860 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4864 /* Mark the state dirty until we have nicer tracking
4865 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4866 * that value.
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4870 This->stateBlock->state.base_vertex_index = 0;
4871 This->up_strided = DrawPrimStrideData;
4872 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4873 This->up_strided = NULL;
4874 return WINED3D_OK;
4877 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4878 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4879 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4882 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4884 /* Mark the state dirty until we have nicer tracking
4885 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4886 * that value.
4888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4890 This->stateBlock->state.user_stream = TRUE;
4891 This->stateBlock->state.base_vertex_index = 0;
4892 This->up_strided = DrawPrimStrideData;
4893 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4894 This->up_strided = NULL;
4895 return WINED3D_OK;
4898 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4899 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4900 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4902 WINED3DLOCKED_BOX src;
4903 WINED3DLOCKED_BOX dst;
4904 HRESULT hr;
4906 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4907 iface, pSourceVolume, pDestinationVolume);
4909 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4910 * dirtification to improve loading performance.
4912 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4913 if(FAILED(hr)) return hr;
4914 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4915 if(FAILED(hr)) {
4916 IWineD3DVolume_UnlockBox(pSourceVolume);
4917 return hr;
4920 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4922 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4923 if(FAILED(hr)) {
4924 IWineD3DVolume_UnlockBox(pSourceVolume);
4925 } else {
4926 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4928 return hr;
4931 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4932 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4934 unsigned int level_count, i;
4935 WINED3DRESOURCETYPE type;
4936 HRESULT hr;
4938 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4940 /* Verify that the source and destination textures are non-NULL. */
4941 if (!src_texture || !dst_texture)
4943 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4944 return WINED3DERR_INVALIDCALL;
4947 if (src_texture == dst_texture)
4949 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4950 return WINED3DERR_INVALIDCALL;
4953 /* Verify that the source and destination textures are the same type. */
4954 type = IWineD3DBaseTexture_GetType(src_texture);
4955 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4957 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4958 return WINED3DERR_INVALIDCALL;
4961 /* Check that both textures have the identical numbers of levels. */
4962 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4963 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4965 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4966 return WINED3DERR_INVALIDCALL;
4969 /* Make sure that the destination texture is loaded. */
4970 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4972 /* Update every surface level of the texture. */
4973 switch (type)
4975 case WINED3DRTYPE_TEXTURE:
4977 IWineD3DSurface *src_surface;
4978 IWineD3DSurface *dst_surface;
4980 for (i = 0; i < level_count; ++i)
4982 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4983 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4984 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4985 IWineD3DSurface_Release(dst_surface);
4986 IWineD3DSurface_Release(src_surface);
4987 if (FAILED(hr))
4989 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4990 return hr;
4993 break;
4996 case WINED3DRTYPE_CUBETEXTURE:
4998 IWineD3DSurface *src_surface;
4999 IWineD3DSurface *dst_surface;
5000 WINED3DCUBEMAP_FACES face;
5002 for (i = 0; i < level_count; ++i)
5004 /* Update each cube face. */
5005 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5007 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5008 face, i, &src_surface);
5009 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5010 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5011 face, i, &dst_surface);
5012 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5013 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5014 IWineD3DSurface_Release(dst_surface);
5015 IWineD3DSurface_Release(src_surface);
5016 if (FAILED(hr))
5018 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5019 return hr;
5023 break;
5026 case WINED3DRTYPE_VOLUMETEXTURE:
5028 IWineD3DVolume *src_volume;
5029 IWineD3DVolume *dst_volume;
5031 for (i = 0; i < level_count; ++i)
5033 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5034 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5035 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5036 IWineD3DVolume_Release(dst_volume);
5037 IWineD3DVolume_Release(src_volume);
5038 if (FAILED(hr))
5040 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5041 return hr;
5044 break;
5047 default:
5048 FIXME("Unsupported texture type %#x.\n", type);
5049 return WINED3DERR_INVALIDCALL;
5052 return WINED3D_OK;
5055 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5056 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5058 IWineD3DSwapChain *swapchain;
5059 HRESULT hr;
5061 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5063 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5064 if (FAILED(hr)) return hr;
5066 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5067 IWineD3DSwapChain_Release(swapchain);
5069 return hr;
5072 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5074 IWineD3DBaseTextureImpl *texture;
5075 DWORD i;
5077 TRACE("(%p) : %p\n", This, pNumPasses);
5079 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5081 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5083 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5084 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5086 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5088 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5089 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5092 texture = This->stateBlock->state.textures[i];
5093 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5095 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5097 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5098 return E_FAIL;
5100 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5102 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5103 return E_FAIL;
5105 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5106 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5108 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5109 return E_FAIL;
5113 /* return a sensible default */
5114 *pNumPasses = 1;
5116 TRACE("returning D3D_OK\n");
5117 return WINED3D_OK;
5120 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5122 int i;
5124 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5126 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5127 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5128 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5130 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5135 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 int j;
5138 UINT NewSize;
5139 PALETTEENTRY **palettes;
5141 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5143 if (PaletteNumber >= MAX_PALETTES) {
5144 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5145 return WINED3DERR_INVALIDCALL;
5148 if (PaletteNumber >= This->NumberOfPalettes) {
5149 NewSize = This->NumberOfPalettes;
5150 do {
5151 NewSize *= 2;
5152 } while(PaletteNumber >= NewSize);
5153 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5154 if (!palettes) {
5155 ERR("Out of memory!\n");
5156 return E_OUTOFMEMORY;
5158 This->palettes = palettes;
5159 This->NumberOfPalettes = NewSize;
5162 if (!This->palettes[PaletteNumber]) {
5163 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5164 if (!This->palettes[PaletteNumber]) {
5165 ERR("Out of memory!\n");
5166 return E_OUTOFMEMORY;
5170 for (j = 0; j < 256; ++j) {
5171 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5172 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5173 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5174 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5176 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5177 TRACE("(%p) : returning\n", This);
5178 return WINED3D_OK;
5181 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5183 int j;
5184 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5185 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5186 /* What happens in such situation isn't documented; Native seems to silently abort
5187 on such conditions. Return Invalid Call. */
5188 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5189 return WINED3DERR_INVALIDCALL;
5191 for (j = 0; j < 256; ++j) {
5192 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5193 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5194 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5195 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5197 TRACE("(%p) : returning\n", This);
5198 return WINED3D_OK;
5201 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5204 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5205 (tested with reference rasterizer). Return Invalid Call. */
5206 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5207 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5208 return WINED3DERR_INVALIDCALL;
5210 /*TODO: stateblocks */
5211 if (This->currentPalette != PaletteNumber) {
5212 This->currentPalette = PaletteNumber;
5213 dirtify_p8_texture_samplers(This);
5215 TRACE("(%p) : returning\n", This);
5216 return WINED3D_OK;
5219 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5222 if (!PaletteNumber)
5224 WARN("(%p) : returning Invalid Call\n", This);
5225 return WINED3DERR_INVALIDCALL;
5227 /*TODO: stateblocks */
5228 *PaletteNumber = This->currentPalette;
5229 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5230 return WINED3D_OK;
5233 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 static BOOL warned;
5236 if (!warned)
5238 FIXME("(%p) : stub\n", This);
5239 warned = TRUE;
5242 This->softwareVertexProcessing = bSoftware;
5243 return WINED3D_OK;
5247 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5249 static BOOL warned;
5250 if (!warned)
5252 FIXME("(%p) : stub\n", This);
5253 warned = TRUE;
5255 return This->softwareVertexProcessing;
5258 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5259 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5261 IWineD3DSwapChain *swapchain;
5262 HRESULT hr;
5264 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5265 iface, swapchain_idx, raster_status);
5267 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5268 if (FAILED(hr))
5270 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5271 return hr;
5274 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5275 IWineD3DSwapChain_Release(swapchain);
5276 if (FAILED(hr))
5278 WARN("Failed to get raster status, hr %#x.\n", hr);
5279 return hr;
5282 return WINED3D_OK;
5285 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5287 static BOOL warned;
5288 if(nSegments != 0.0f) {
5289 if (!warned)
5291 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5292 warned = TRUE;
5295 return WINED3D_OK;
5298 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5300 static BOOL warned;
5301 if (!warned)
5303 FIXME("iface %p stub!\n", iface);
5304 warned = TRUE;
5306 return 0.0f;
5309 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5310 IWineD3DSurface *src_surface, const RECT *src_rect,
5311 IWineD3DSurface *dst_surface, const POINT *dst_point)
5313 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5314 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 const struct wined3d_format *src_format;
5317 const struct wined3d_format *dst_format;
5318 const struct wined3d_gl_info *gl_info;
5319 struct wined3d_context *context;
5320 const unsigned char *data;
5321 UINT update_w, update_h;
5322 CONVERT_TYPES convert;
5323 UINT src_w, src_h;
5324 UINT dst_x, dst_y;
5325 DWORD sampler;
5326 struct wined3d_format format;
5328 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5329 iface, src_surface, wine_dbgstr_rect(src_rect),
5330 dst_surface, wine_dbgstr_point(dst_point));
5332 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5334 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5335 src_surface, dst_surface);
5336 return WINED3DERR_INVALIDCALL;
5339 src_format = src_impl->resource.format;
5340 dst_format = dst_impl->resource.format;
5342 if (src_format->id != dst_format->id)
5344 WARN("Source and destination surfaces should have the same format.\n");
5345 return WINED3DERR_INVALIDCALL;
5348 dst_x = dst_point ? dst_point->x : 0;
5349 dst_y = dst_point ? dst_point->y : 0;
5351 /* This call loads the OpenGL surface directly, instead of copying the
5352 * surface to the destination's sysmem copy. If surface conversion is
5353 * needed, use BltFast instead to copy in sysmem and use regular surface
5354 * loading. */
5355 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5356 if (convert != NO_CONVERSION || format.convert)
5357 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5359 context = context_acquire(This, NULL);
5360 gl_info = context->gl_info;
5362 ENTER_GL();
5363 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5364 checkGLcall("glActiveTextureARB");
5365 LEAVE_GL();
5367 /* Make sure the surface is loaded and up to date */
5368 surface_internal_preload(dst_impl, SRGB_RGB);
5369 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5371 src_w = src_impl->currentDesc.Width;
5372 src_h = src_impl->currentDesc.Height;
5373 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5374 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5376 data = IWineD3DSurface_GetData(src_surface);
5377 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5379 ENTER_GL();
5381 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5383 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5384 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5385 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5387 if (src_rect)
5389 data += (src_rect->top / src_format->block_height) * src_pitch;
5390 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5393 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5394 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5395 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5397 if (row_length == src_pitch)
5399 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5400 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5402 else
5404 UINT row, y;
5406 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5407 * can't use the unpack row length like below. */
5408 for (row = 0, y = dst_y; row < row_count; ++row)
5410 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5411 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5412 y += src_format->block_height;
5413 data += src_pitch;
5416 checkGLcall("glCompressedTexSubImage2DARB");
5418 else
5420 if (src_rect)
5422 data += src_rect->top * src_w * src_format->byte_count;
5423 data += src_rect->left * src_format->byte_count;
5426 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5427 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5428 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5430 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5431 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5432 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5433 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5434 checkGLcall("glTexSubImage2D");
5437 LEAVE_GL();
5438 context_release(context);
5440 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5441 sampler = This->rev_tex_unit_map[0];
5442 if (sampler != WINED3D_UNMAPPED_STAGE)
5444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5447 return WINED3D_OK;
5450 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5452 struct WineD3DRectPatch *patch;
5453 GLenum old_primitive_type;
5454 unsigned int i;
5455 struct list *e;
5456 BOOL found;
5457 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5459 if(!(Handle || pRectPatchInfo)) {
5460 /* TODO: Write a test for the return value, thus the FIXME */
5461 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5462 return WINED3DERR_INVALIDCALL;
5465 if(Handle) {
5466 i = PATCHMAP_HASHFUNC(Handle);
5467 found = FALSE;
5468 LIST_FOR_EACH(e, &This->patches[i]) {
5469 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5470 if(patch->Handle == Handle) {
5471 found = TRUE;
5472 break;
5476 if(!found) {
5477 TRACE("Patch does not exist. Creating a new one\n");
5478 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5479 patch->Handle = Handle;
5480 list_add_head(&This->patches[i], &patch->entry);
5481 } else {
5482 TRACE("Found existing patch %p\n", patch);
5484 } else {
5485 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5486 * attributes we have to tesselate, read back, and draw. This needs a patch
5487 * management structure instance. Create one.
5489 * A possible improvement is to check if a vertex shader is used, and if not directly
5490 * draw the patch.
5492 FIXME("Drawing an uncached patch. This is slow\n");
5493 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5496 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5497 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5498 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5500 HRESULT hr;
5501 TRACE("Tesselation density or patch info changed, retesselating\n");
5503 if(pRectPatchInfo) {
5504 patch->RectPatchInfo = *pRectPatchInfo;
5506 patch->numSegs[0] = pNumSegs[0];
5507 patch->numSegs[1] = pNumSegs[1];
5508 patch->numSegs[2] = pNumSegs[2];
5509 patch->numSegs[3] = pNumSegs[3];
5511 hr = tesselate_rectpatch(This, patch);
5512 if(FAILED(hr)) {
5513 WARN("Patch tesselation failed\n");
5515 /* Do not release the handle to store the params of the patch */
5516 if(!Handle) {
5517 HeapFree(GetProcessHeap(), 0, patch);
5519 return hr;
5523 This->currentPatch = patch;
5524 old_primitive_type = This->stateBlock->state.gl_primitive_type;
5525 This->stateBlock->state.gl_primitive_type = GL_TRIANGLES;
5526 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5527 This->stateBlock->state.gl_primitive_type = old_primitive_type;
5528 This->currentPatch = NULL;
5530 /* Destroy uncached patches */
5531 if(!Handle) {
5532 HeapFree(GetProcessHeap(), 0, patch->mem);
5533 HeapFree(GetProcessHeap(), 0, patch);
5535 return WINED3D_OK;
5538 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5539 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5541 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5542 iface, handle, segment_count, patch_info);
5544 return WINED3D_OK;
5547 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5549 int i;
5550 struct WineD3DRectPatch *patch;
5551 struct list *e;
5552 TRACE("(%p) Handle(%d)\n", This, Handle);
5554 i = PATCHMAP_HASHFUNC(Handle);
5555 LIST_FOR_EACH(e, &This->patches[i]) {
5556 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5557 if(patch->Handle == Handle) {
5558 TRACE("Deleting patch %p\n", patch);
5559 list_remove(&patch->entry);
5560 HeapFree(GetProcessHeap(), 0, patch->mem);
5561 HeapFree(GetProcessHeap(), 0, patch);
5562 return WINED3D_OK;
5566 /* TODO: Write a test for the return value */
5567 FIXME("Attempt to destroy nonexistent patch\n");
5568 return WINED3DERR_INVALIDCALL;
5571 /* Do not call while under the GL lock. */
5572 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5573 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5575 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5577 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5578 iface, surface, wine_dbgstr_rect(rect),
5579 color->r, color->g, color->b, color->a);
5581 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5583 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5584 return WINED3DERR_INVALIDCALL;
5587 return surface_color_fill(s, rect, color);
5590 /* Do not call while under the GL lock. */
5591 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5592 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5594 IWineD3DResource *resource;
5595 HRESULT hr;
5597 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5598 if (FAILED(hr))
5600 ERR("Failed to get resource, hr %#x\n", hr);
5601 return;
5604 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5606 FIXME("Only supported on surface resources\n");
5607 IWineD3DResource_Release(resource);
5608 return;
5611 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5612 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5614 IWineD3DResource_Release(resource);
5617 /* rendertarget and depth stencil functions */
5618 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5619 DWORD render_target_idx, IWineD3DSurface **render_target)
5621 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5623 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5624 iface, render_target_idx, render_target);
5626 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5628 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5629 return WINED3DERR_INVALIDCALL;
5632 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5633 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5635 TRACE("Returning render target %p.\n", *render_target);
5637 return WINED3D_OK;
5640 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5641 IWineD3DSurface *front, IWineD3DSurface *back)
5643 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5644 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5645 IWineD3DSwapChainImpl *swapchain;
5646 HRESULT hr;
5648 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5650 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5652 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5653 return hr;
5656 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5658 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5659 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5660 return WINED3DERR_INVALIDCALL;
5663 if (back_impl)
5665 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5667 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5668 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5669 return WINED3DERR_INVALIDCALL;
5672 if (!swapchain->back_buffers)
5674 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5675 if (!swapchain->back_buffers)
5677 ERR("Failed to allocate back buffer array memory.\n");
5678 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5679 return E_OUTOFMEMORY;
5684 if (swapchain->front_buffer != front_impl)
5686 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5688 if (swapchain->front_buffer)
5689 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5690 swapchain->front_buffer = front_impl;
5692 if (front_impl)
5693 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5696 if (swapchain->back_buffers[0] != back_impl)
5698 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5700 if (swapchain->back_buffers[0])
5701 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5702 swapchain->back_buffers[0] = back_impl;
5704 if (back_impl)
5706 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5707 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5708 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5709 swapchain->presentParms.BackBufferCount = 1;
5711 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5713 else
5715 swapchain->presentParms.BackBufferCount = 0;
5716 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5717 swapchain->back_buffers = NULL;
5721 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5722 return WINED3D_OK;
5725 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5727 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5729 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5731 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5732 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5733 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5734 IWineD3DSurface_AddRef(*depth_stencil);
5736 return WINED3D_OK;
5739 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5740 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5742 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5743 IWineD3DSurfaceImpl *prev;
5745 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5746 iface, render_target_idx, render_target, set_viewport);
5748 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5750 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5751 return WINED3DERR_INVALIDCALL;
5754 prev = device->render_targets[render_target_idx];
5755 if (render_target == (IWineD3DSurface *)prev)
5757 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5758 return WINED3D_OK;
5761 /* Render target 0 can't be set to NULL. */
5762 if (!render_target && !render_target_idx)
5764 WARN("Trying to set render target 0 to NULL.\n");
5765 return WINED3DERR_INVALIDCALL;
5768 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5770 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5771 return WINED3DERR_INVALIDCALL;
5774 if (render_target) IWineD3DSurface_AddRef(render_target);
5775 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5776 /* Release after the assignment, to prevent device_resource_released()
5777 * from seeing the surface as still in use. */
5778 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5780 /* Render target 0 is special. */
5781 if (!render_target_idx && set_viewport)
5783 /* Set the viewport and scissor rectangles, if requested. Tests show
5784 * that stateblock recording is ignored, the change goes directly
5785 * into the primary stateblock. */
5786 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5787 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5788 device->stateBlock->state.viewport.X = 0;
5789 device->stateBlock->state.viewport.Y = 0;
5790 device->stateBlock->state.viewport.MaxZ = 1.0f;
5791 device->stateBlock->state.viewport.MinZ = 0.0f;
5792 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5794 device->stateBlock->state.scissor_rect.top = 0;
5795 device->stateBlock->state.scissor_rect.left = 0;
5796 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5797 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5798 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5801 return WINED3D_OK;
5804 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5807 IWineD3DSurfaceImpl *tmp;
5809 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5811 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5813 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5814 return WINED3D_OK;
5817 if (This->depth_stencil)
5819 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5820 || This->depth_stencil->Flags & SFLAG_DISCARD)
5822 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5823 This->depth_stencil->currentDesc.Width,
5824 This->depth_stencil->currentDesc.Height);
5825 if (This->depth_stencil == This->onscreen_depth_stencil)
5827 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5828 This->onscreen_depth_stencil = NULL;
5833 tmp = This->depth_stencil;
5834 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5835 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5836 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5838 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5840 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5846 return WINED3D_OK;
5849 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5850 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5853 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5854 WINED3DLOCKED_RECT lockedRect;
5856 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5857 iface, XHotSpot, YHotSpot, cursor_image);
5859 /* some basic validation checks */
5860 if (This->cursorTexture)
5862 struct wined3d_context *context = context_acquire(This, NULL);
5863 ENTER_GL();
5864 glDeleteTextures(1, &This->cursorTexture);
5865 LEAVE_GL();
5866 context_release(context);
5867 This->cursorTexture = 0;
5870 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5871 This->haveHardwareCursor = TRUE;
5872 else
5873 This->haveHardwareCursor = FALSE;
5875 if (cursor_image)
5877 WINED3DLOCKED_RECT rect;
5879 /* MSDN: Cursor must be A8R8G8B8 */
5880 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5882 WARN("surface %p has an invalid format.\n", cursor_image);
5883 return WINED3DERR_INVALIDCALL;
5886 /* MSDN: Cursor must be smaller than the display mode */
5887 if (s->currentDesc.Width > This->ddraw_width
5888 || s->currentDesc.Height > This->ddraw_height)
5890 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5891 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5892 return WINED3DERR_INVALIDCALL;
5895 if (!This->haveHardwareCursor) {
5896 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5898 /* Do not store the surface's pointer because the application may
5899 * release it after setting the cursor image. Windows doesn't
5900 * addref the set surface, so we can't do this either without
5901 * creating circular refcount dependencies. Copy out the gl texture
5902 * instead.
5904 This->cursorWidth = s->currentDesc.Width;
5905 This->cursorHeight = s->currentDesc.Height;
5906 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5908 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5909 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5910 struct wined3d_context *context;
5911 char *mem, *bits = rect.pBits;
5912 GLint intfmt = format->glInternal;
5913 GLint gl_format = format->glFormat;
5914 GLint type = format->glType;
5915 INT height = This->cursorHeight;
5916 INT width = This->cursorWidth;
5917 INT bpp = format->byte_count;
5918 DWORD sampler;
5919 INT i;
5921 /* Reformat the texture memory (pitch and width can be
5922 * different) */
5923 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5924 for(i = 0; i < height; i++)
5925 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5926 IWineD3DSurface_UnlockRect(cursor_image);
5928 context = context_acquire(This, NULL);
5930 ENTER_GL();
5932 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5934 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5935 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5938 /* Make sure that a proper texture unit is selected */
5939 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5940 checkGLcall("glActiveTextureARB");
5941 sampler = This->rev_tex_unit_map[0];
5942 if (sampler != WINED3D_UNMAPPED_STAGE)
5944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5946 /* Create a new cursor texture */
5947 glGenTextures(1, &This->cursorTexture);
5948 checkGLcall("glGenTextures");
5949 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5950 checkGLcall("glBindTexture");
5951 /* Copy the bitmap memory into the cursor texture */
5952 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5953 HeapFree(GetProcessHeap(), 0, mem);
5954 checkGLcall("glTexImage2D");
5956 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5958 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5959 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5962 LEAVE_GL();
5964 context_release(context);
5966 else
5968 FIXME("A cursor texture was not returned.\n");
5969 This->cursorTexture = 0;
5972 else
5974 /* Draw a hardware cursor */
5975 ICONINFO cursorInfo;
5976 HCURSOR cursor;
5977 /* Create and clear maskBits because it is not needed for
5978 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5979 * chunks. */
5980 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5981 (s->currentDesc.Width * s->currentDesc.Height / 8));
5982 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5983 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5984 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5986 cursorInfo.fIcon = FALSE;
5987 cursorInfo.xHotspot = XHotSpot;
5988 cursorInfo.yHotspot = YHotSpot;
5989 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5990 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5991 IWineD3DSurface_UnlockRect(cursor_image);
5992 /* Create our cursor and clean up. */
5993 cursor = CreateIconIndirect(&cursorInfo);
5994 SetCursor(cursor);
5995 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5996 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5997 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5998 This->hardwareCursor = cursor;
5999 HeapFree(GetProcessHeap(), 0, maskBits);
6003 This->xHotSpot = XHotSpot;
6004 This->yHotSpot = YHotSpot;
6005 return WINED3D_OK;
6008 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6010 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6012 This->xScreenSpace = XScreenSpace;
6013 This->yScreenSpace = YScreenSpace;
6015 return;
6019 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6021 BOOL oldVisible = This->bCursorVisible;
6022 POINT pt;
6024 TRACE("(%p) : visible(%d)\n", This, bShow);
6027 * When ShowCursor is first called it should make the cursor appear at the OS's last
6028 * known cursor position. Because of this, some applications just repetitively call
6029 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6031 GetCursorPos(&pt);
6032 This->xScreenSpace = pt.x;
6033 This->yScreenSpace = pt.y;
6035 if (This->haveHardwareCursor) {
6036 This->bCursorVisible = bShow;
6037 if (bShow)
6038 SetCursor(This->hardwareCursor);
6039 else
6040 SetCursor(NULL);
6042 else
6044 if (This->cursorTexture)
6045 This->bCursorVisible = bShow;
6048 return oldVisible;
6051 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6052 TRACE("checking resource %p for eviction\n", resource);
6053 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6054 TRACE("Evicting %p\n", resource);
6055 IWineD3DResource_UnLoad(resource);
6057 IWineD3DResource_Release(resource);
6058 return S_OK;
6061 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6063 TRACE("iface %p.\n", iface);
6065 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6066 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6067 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6069 return WINED3D_OK;
6072 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6074 IWineD3DDeviceImpl *device = surface->resource.device;
6075 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6077 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6078 if(surface->Flags & SFLAG_DIBSECTION) {
6079 /* Release the DC */
6080 SelectObject(surface->hDC, surface->dib.holdbitmap);
6081 DeleteDC(surface->hDC);
6082 /* Release the DIB section */
6083 DeleteObject(surface->dib.DIBsection);
6084 surface->dib.bitmap_data = NULL;
6085 surface->resource.allocatedMemory = NULL;
6086 surface->Flags &= ~SFLAG_DIBSECTION;
6088 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6089 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6090 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6091 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6093 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6094 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6095 } else {
6096 surface->pow2Width = surface->pow2Height = 1;
6097 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6098 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6101 if (surface->texture_name)
6103 struct wined3d_context *context = context_acquire(device, NULL);
6104 ENTER_GL();
6105 glDeleteTextures(1, &surface->texture_name);
6106 LEAVE_GL();
6107 context_release(context);
6108 surface->texture_name = 0;
6109 surface->Flags &= ~SFLAG_CLIENT;
6111 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6112 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6113 surface->Flags |= SFLAG_NONPOW2;
6114 } else {
6115 surface->Flags &= ~SFLAG_NONPOW2;
6117 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6118 surface->resource.allocatedMemory = NULL;
6119 surface->resource.heapMemory = NULL;
6120 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6122 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6123 * to a FBO */
6124 if (!surface_init_sysmem(surface))
6126 return E_OUTOFMEMORY;
6128 return WINED3D_OK;
6131 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6132 TRACE("Unloading resource %p\n", resource);
6133 IWineD3DResource_UnLoad(resource);
6134 IWineD3DResource_Release(resource);
6135 return S_OK;
6138 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6140 UINT i, count;
6141 WINED3DDISPLAYMODE m;
6142 HRESULT hr;
6144 /* All Windowed modes are supported, as is leaving the current mode */
6145 if(pp->Windowed) return TRUE;
6146 if(!pp->BackBufferWidth) return TRUE;
6147 if(!pp->BackBufferHeight) return TRUE;
6149 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6150 for(i = 0; i < count; i++) {
6151 memset(&m, 0, sizeof(m));
6152 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6153 if(FAILED(hr)) {
6154 ERR("EnumAdapterModes failed\n");
6156 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6157 /* Mode found, it is supported */
6158 return TRUE;
6161 /* Mode not found -> not supported */
6162 return FALSE;
6165 /* Do not call while under the GL lock. */
6166 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6169 const struct wined3d_gl_info *gl_info;
6170 struct wined3d_context *context;
6171 IWineD3DBaseShaderImpl *shader;
6173 context = context_acquire(This, NULL);
6174 gl_info = context->gl_info;
6176 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6177 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6178 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6181 ENTER_GL();
6182 if(This->depth_blt_texture) {
6183 glDeleteTextures(1, &This->depth_blt_texture);
6184 This->depth_blt_texture = 0;
6186 if (This->depth_blt_rb) {
6187 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6188 This->depth_blt_rb = 0;
6189 This->depth_blt_rb_w = 0;
6190 This->depth_blt_rb_h = 0;
6192 LEAVE_GL();
6194 This->blitter->free_private(iface);
6195 This->frag_pipe->free_private(iface);
6196 This->shader_backend->shader_free_private(iface);
6197 destroy_dummy_textures(This, gl_info);
6199 context_release(context);
6201 while (This->numContexts)
6203 context_destroy(This, This->contexts[0]);
6205 HeapFree(GetProcessHeap(), 0, swapchain->context);
6206 swapchain->context = NULL;
6207 swapchain->num_contexts = 0;
6210 /* Do not call while under the GL lock. */
6211 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6214 struct wined3d_context *context;
6215 HRESULT hr;
6216 IWineD3DSurfaceImpl *target;
6218 /* Recreate the primary swapchain's context */
6219 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6220 if (!swapchain->context)
6222 ERR("Failed to allocate memory for swapchain context array.\n");
6223 return E_OUTOFMEMORY;
6226 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6227 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6229 WARN("Failed to create context.\n");
6230 HeapFree(GetProcessHeap(), 0, swapchain->context);
6231 return E_FAIL;
6234 swapchain->context[0] = context;
6235 swapchain->num_contexts = 1;
6236 create_dummy_textures(This);
6237 context_release(context);
6239 hr = This->shader_backend->shader_alloc_private(iface);
6240 if (FAILED(hr))
6242 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6243 goto err;
6246 hr = This->frag_pipe->alloc_private(iface);
6247 if (FAILED(hr))
6249 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6250 This->shader_backend->shader_free_private(iface);
6251 goto err;
6254 hr = This->blitter->alloc_private(iface);
6255 if (FAILED(hr))
6257 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6258 This->frag_pipe->free_private(iface);
6259 This->shader_backend->shader_free_private(iface);
6260 goto err;
6263 return WINED3D_OK;
6265 err:
6266 context_acquire(This, NULL);
6267 destroy_dummy_textures(This, context->gl_info);
6268 context_release(context);
6269 context_destroy(This, context);
6270 HeapFree(GetProcessHeap(), 0, swapchain->context);
6271 swapchain->num_contexts = 0;
6272 return hr;
6275 /* Do not call while under the GL lock. */
6276 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6277 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6280 IWineD3DSwapChainImpl *swapchain;
6281 HRESULT hr;
6282 BOOL DisplayModeChanged = FALSE;
6283 WINED3DDISPLAYMODE mode;
6284 TRACE("(%p)\n", This);
6286 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6287 if(FAILED(hr)) {
6288 ERR("Failed to get the first implicit swapchain\n");
6289 return hr;
6292 if(!is_display_mode_supported(This, pPresentationParameters)) {
6293 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6294 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6295 pPresentationParameters->BackBufferHeight);
6296 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6297 return WINED3DERR_INVALIDCALL;
6300 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6301 * on an existing gl context, so there's no real need for recreation.
6303 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6305 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6307 TRACE("New params:\n");
6308 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6309 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6310 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6311 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6312 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6313 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6314 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6315 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6316 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6317 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6318 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6319 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6320 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6322 /* No special treatment of these parameters. Just store them */
6323 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6324 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6325 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6326 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6328 /* What to do about these? */
6329 if (pPresentationParameters->BackBufferCount
6330 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6331 ERR("Cannot change the back buffer count yet\n");
6333 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6334 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6335 ERR("Cannot change the back buffer format yet\n");
6338 if (pPresentationParameters->hDeviceWindow
6339 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6340 ERR("Cannot change the device window yet\n");
6342 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6344 HRESULT hrc;
6346 TRACE("Creating the depth stencil buffer\n");
6348 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6349 pPresentationParameters->BackBufferWidth,
6350 pPresentationParameters->BackBufferHeight,
6351 pPresentationParameters->AutoDepthStencilFormat,
6352 pPresentationParameters->MultiSampleType,
6353 pPresentationParameters->MultiSampleQuality,
6354 FALSE,
6355 (IWineD3DSurface **)&This->auto_depth_stencil);
6357 if (FAILED(hrc)) {
6358 ERR("Failed to create the depth stencil buffer\n");
6359 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6360 return WINED3DERR_INVALIDCALL;
6364 if (This->onscreen_depth_stencil)
6366 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6367 This->onscreen_depth_stencil = NULL;
6370 /* Reset the depth stencil */
6371 if (pPresentationParameters->EnableAutoDepthStencil)
6372 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6373 else
6374 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6376 TRACE("Resetting stateblock\n");
6377 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6378 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6380 delete_opengl_contexts(iface, swapchain);
6382 if(pPresentationParameters->Windowed) {
6383 mode.Width = swapchain->orig_width;
6384 mode.Height = swapchain->orig_height;
6385 mode.RefreshRate = 0;
6386 mode.Format = swapchain->presentParms.BackBufferFormat;
6387 } else {
6388 mode.Width = pPresentationParameters->BackBufferWidth;
6389 mode.Height = pPresentationParameters->BackBufferHeight;
6390 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6391 mode.Format = swapchain->presentParms.BackBufferFormat;
6394 /* Should Width == 800 && Height == 0 set 800x600? */
6395 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6396 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6397 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6399 UINT i;
6401 if(!pPresentationParameters->Windowed) {
6402 DisplayModeChanged = TRUE;
6404 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6405 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6407 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6408 if(FAILED(hr))
6410 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6411 return hr;
6414 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6416 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6417 if(FAILED(hr))
6419 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6420 return hr;
6423 if (This->auto_depth_stencil)
6425 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6426 if(FAILED(hr))
6428 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6429 return hr;
6434 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6435 || DisplayModeChanged)
6437 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6439 if (!pPresentationParameters->Windowed)
6441 if(swapchain->presentParms.Windowed) {
6442 /* switch from windowed to fs */
6443 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6444 pPresentationParameters->BackBufferHeight);
6445 } else {
6446 /* Fullscreen -> fullscreen mode change */
6447 MoveWindow(swapchain->device_window, 0, 0,
6448 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6449 TRUE);
6452 else if (!swapchain->presentParms.Windowed)
6454 /* Fullscreen -> windowed switch */
6455 swapchain_restore_fullscreen_window(swapchain);
6457 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6458 } else if(!pPresentationParameters->Windowed) {
6459 DWORD style = This->style, exStyle = This->exStyle;
6460 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6461 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6462 * Reset to clear up their mess. Guild Wars also loses the device during that.
6464 This->style = 0;
6465 This->exStyle = 0;
6466 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6467 pPresentationParameters->BackBufferHeight);
6468 This->style = style;
6469 This->exStyle = exStyle;
6472 /* Note: No parent needed for initial internal stateblock */
6473 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6474 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6475 else TRACE("Created stateblock %p\n", This->stateBlock);
6476 This->updateStateBlock = This->stateBlock;
6477 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6479 stateblock_init_default_state(This->stateBlock);
6481 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6483 RECT client_rect;
6484 GetClientRect(swapchain->win_handle, &client_rect);
6486 if(!swapchain->presentParms.BackBufferCount)
6488 TRACE("Single buffered rendering\n");
6489 swapchain->render_to_fbo = FALSE;
6491 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6492 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6494 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6495 swapchain->presentParms.BackBufferWidth,
6496 swapchain->presentParms.BackBufferHeight,
6497 client_rect.right, client_rect.bottom);
6498 swapchain->render_to_fbo = TRUE;
6500 else
6502 TRACE("Rendering directly to GL_BACK\n");
6503 swapchain->render_to_fbo = FALSE;
6507 hr = create_primary_opengl_context(iface, swapchain);
6508 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6510 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6511 * first use
6513 return hr;
6516 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6518 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6520 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6522 return WINED3D_OK;
6526 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6528 TRACE("(%p) : pParameters %p\n", This, pParameters);
6530 *pParameters = This->createParms;
6531 return WINED3D_OK;
6534 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6535 IWineD3DSwapChain *swapchain;
6537 TRACE("Relaying to swapchain\n");
6539 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6540 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6541 IWineD3DSwapChain_Release(swapchain);
6545 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6546 IWineD3DSwapChain *swapchain;
6548 TRACE("Relaying to swapchain\n");
6550 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6551 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6552 IWineD3DSwapChain_Release(swapchain);
6557 /** ********************************************************
6558 * Notification functions
6559 ** ********************************************************/
6560 /** This function must be called in the release of a resource when ref == 0,
6561 * the contents of resource must still be correct,
6562 * any handles to other resource held by the caller must be closed
6563 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6564 *****************************************************/
6565 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6567 TRACE("(%p) : Adding resource %p\n", This, resource);
6569 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6572 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6574 TRACE("(%p) : Removing resource %p\n", This, resource);
6576 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6579 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6581 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6582 unsigned int i;
6584 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6586 context_resource_released(device, resource, type);
6588 switch (type)
6590 case WINED3DRTYPE_SURFACE:
6591 if (!device->d3d_initialized) break;
6593 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6595 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6597 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6598 device->render_targets[i] = NULL;
6602 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6604 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6605 device->depth_stencil = NULL;
6607 break;
6609 case WINED3DRTYPE_TEXTURE:
6610 case WINED3DRTYPE_CUBETEXTURE:
6611 case WINED3DRTYPE_VOLUMETEXTURE:
6612 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6614 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6616 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6617 resource, device->stateBlock, i);
6618 device->stateBlock->state.textures[i] = NULL;
6621 if (device->updateStateBlock != device->stateBlock
6622 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6624 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6625 resource, device->updateStateBlock, i);
6626 device->updateStateBlock->state.textures[i] = NULL;
6629 break;
6631 case WINED3DRTYPE_BUFFER:
6632 for (i = 0; i < MAX_STREAMS; ++i)
6634 if (device->stateBlock
6635 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6637 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6638 resource, device->stateBlock, i);
6639 device->stateBlock->state.streams[i].buffer = NULL;
6642 if (device->updateStateBlock != device->stateBlock
6643 && device->updateStateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6645 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6646 resource, device->updateStateBlock, i);
6647 device->updateStateBlock->state.streams[i].buffer = NULL;
6652 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6654 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6655 resource, device->stateBlock);
6656 device->stateBlock->state.index_buffer = NULL;
6659 if (device->updateStateBlock != device->stateBlock
6660 && device->updateStateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6662 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6663 resource, device->updateStateBlock);
6664 device->updateStateBlock->state.index_buffer = NULL;
6666 break;
6668 default:
6669 break;
6672 /* Remove the resource from the resourceStore */
6673 device_resource_remove(device, resource);
6675 TRACE("Resource released.\n");
6678 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6680 IWineD3DResourceImpl *resource, *cursor;
6681 HRESULT ret;
6682 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6684 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6685 TRACE("enumerating resource %p\n", resource);
6686 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6687 ret = pCallback((IWineD3DResource *) resource, pData);
6688 if(ret == S_FALSE) {
6689 TRACE("Canceling enumeration\n");
6690 break;
6693 return WINED3D_OK;
6696 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6699 IWineD3DResourceImpl *resource;
6701 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6703 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6704 if (type == WINED3DRTYPE_SURFACE)
6706 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6708 TRACE("Found surface %p for dc %p.\n", resource, dc);
6709 *surface = (IWineD3DSurface *)resource;
6710 return WINED3D_OK;
6715 return WINED3DERR_INVALIDCALL;
6718 /**********************************************************
6719 * IWineD3DDevice VTbl follows
6720 **********************************************************/
6722 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6724 /*** IUnknown methods ***/
6725 IWineD3DDeviceImpl_QueryInterface,
6726 IWineD3DDeviceImpl_AddRef,
6727 IWineD3DDeviceImpl_Release,
6728 /*** IWineD3DDevice methods ***/
6729 /*** Creation methods**/
6730 IWineD3DDeviceImpl_CreateBuffer,
6731 IWineD3DDeviceImpl_CreateVertexBuffer,
6732 IWineD3DDeviceImpl_CreateIndexBuffer,
6733 IWineD3DDeviceImpl_CreateStateBlock,
6734 IWineD3DDeviceImpl_CreateSurface,
6735 IWineD3DDeviceImpl_CreateRendertargetView,
6736 IWineD3DDeviceImpl_CreateTexture,
6737 IWineD3DDeviceImpl_CreateVolumeTexture,
6738 IWineD3DDeviceImpl_CreateVolume,
6739 IWineD3DDeviceImpl_CreateCubeTexture,
6740 IWineD3DDeviceImpl_CreateQuery,
6741 IWineD3DDeviceImpl_CreateSwapChain,
6742 IWineD3DDeviceImpl_CreateVertexDeclaration,
6743 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6744 IWineD3DDeviceImpl_CreateVertexShader,
6745 IWineD3DDeviceImpl_CreateGeometryShader,
6746 IWineD3DDeviceImpl_CreatePixelShader,
6747 IWineD3DDeviceImpl_CreatePalette,
6748 /*** Odd functions **/
6749 IWineD3DDeviceImpl_Init3D,
6750 IWineD3DDeviceImpl_InitGDI,
6751 IWineD3DDeviceImpl_Uninit3D,
6752 IWineD3DDeviceImpl_UninitGDI,
6753 IWineD3DDeviceImpl_SetMultithreaded,
6754 IWineD3DDeviceImpl_EvictManagedResources,
6755 IWineD3DDeviceImpl_GetAvailableTextureMem,
6756 IWineD3DDeviceImpl_GetBackBuffer,
6757 IWineD3DDeviceImpl_GetCreationParameters,
6758 IWineD3DDeviceImpl_GetDeviceCaps,
6759 IWineD3DDeviceImpl_GetDirect3D,
6760 IWineD3DDeviceImpl_GetDisplayMode,
6761 IWineD3DDeviceImpl_SetDisplayMode,
6762 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6763 IWineD3DDeviceImpl_GetRasterStatus,
6764 IWineD3DDeviceImpl_GetSwapChain,
6765 IWineD3DDeviceImpl_Reset,
6766 IWineD3DDeviceImpl_SetDialogBoxMode,
6767 IWineD3DDeviceImpl_SetCursorProperties,
6768 IWineD3DDeviceImpl_SetCursorPosition,
6769 IWineD3DDeviceImpl_ShowCursor,
6770 /*** Getters and setters **/
6771 IWineD3DDeviceImpl_SetClipPlane,
6772 IWineD3DDeviceImpl_GetClipPlane,
6773 IWineD3DDeviceImpl_SetClipStatus,
6774 IWineD3DDeviceImpl_GetClipStatus,
6775 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6776 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6777 IWineD3DDeviceImpl_SetDepthStencilSurface,
6778 IWineD3DDeviceImpl_GetDepthStencilSurface,
6779 IWineD3DDeviceImpl_SetGammaRamp,
6780 IWineD3DDeviceImpl_GetGammaRamp,
6781 IWineD3DDeviceImpl_SetIndexBuffer,
6782 IWineD3DDeviceImpl_GetIndexBuffer,
6783 IWineD3DDeviceImpl_SetBaseVertexIndex,
6784 IWineD3DDeviceImpl_GetBaseVertexIndex,
6785 IWineD3DDeviceImpl_SetLight,
6786 IWineD3DDeviceImpl_GetLight,
6787 IWineD3DDeviceImpl_SetLightEnable,
6788 IWineD3DDeviceImpl_GetLightEnable,
6789 IWineD3DDeviceImpl_SetMaterial,
6790 IWineD3DDeviceImpl_GetMaterial,
6791 IWineD3DDeviceImpl_SetNPatchMode,
6792 IWineD3DDeviceImpl_GetNPatchMode,
6793 IWineD3DDeviceImpl_SetPaletteEntries,
6794 IWineD3DDeviceImpl_GetPaletteEntries,
6795 IWineD3DDeviceImpl_SetPixelShader,
6796 IWineD3DDeviceImpl_GetPixelShader,
6797 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6798 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6799 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6800 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6801 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6802 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6803 IWineD3DDeviceImpl_SetRenderState,
6804 IWineD3DDeviceImpl_GetRenderState,
6805 IWineD3DDeviceImpl_SetRenderTarget,
6806 IWineD3DDeviceImpl_GetRenderTarget,
6807 IWineD3DDeviceImpl_SetFrontBackBuffers,
6808 IWineD3DDeviceImpl_SetSamplerState,
6809 IWineD3DDeviceImpl_GetSamplerState,
6810 IWineD3DDeviceImpl_SetScissorRect,
6811 IWineD3DDeviceImpl_GetScissorRect,
6812 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6813 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6814 IWineD3DDeviceImpl_SetStreamSource,
6815 IWineD3DDeviceImpl_GetStreamSource,
6816 IWineD3DDeviceImpl_SetStreamSourceFreq,
6817 IWineD3DDeviceImpl_GetStreamSourceFreq,
6818 IWineD3DDeviceImpl_SetTexture,
6819 IWineD3DDeviceImpl_GetTexture,
6820 IWineD3DDeviceImpl_SetTextureStageState,
6821 IWineD3DDeviceImpl_GetTextureStageState,
6822 IWineD3DDeviceImpl_SetTransform,
6823 IWineD3DDeviceImpl_GetTransform,
6824 IWineD3DDeviceImpl_SetVertexDeclaration,
6825 IWineD3DDeviceImpl_GetVertexDeclaration,
6826 IWineD3DDeviceImpl_SetVertexShader,
6827 IWineD3DDeviceImpl_GetVertexShader,
6828 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6829 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6830 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6831 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6832 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6833 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6834 IWineD3DDeviceImpl_SetViewport,
6835 IWineD3DDeviceImpl_GetViewport,
6836 IWineD3DDeviceImpl_MultiplyTransform,
6837 IWineD3DDeviceImpl_ValidateDevice,
6838 IWineD3DDeviceImpl_ProcessVertices,
6839 /*** State block ***/
6840 IWineD3DDeviceImpl_BeginStateBlock,
6841 IWineD3DDeviceImpl_EndStateBlock,
6842 /*** Scene management ***/
6843 IWineD3DDeviceImpl_BeginScene,
6844 IWineD3DDeviceImpl_EndScene,
6845 IWineD3DDeviceImpl_Present,
6846 IWineD3DDeviceImpl_Clear,
6847 IWineD3DDeviceImpl_ClearRendertargetView,
6848 /*** Drawing ***/
6849 IWineD3DDeviceImpl_SetPrimitiveType,
6850 IWineD3DDeviceImpl_GetPrimitiveType,
6851 IWineD3DDeviceImpl_DrawPrimitive,
6852 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6853 IWineD3DDeviceImpl_DrawPrimitiveUP,
6854 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6855 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6856 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6857 IWineD3DDeviceImpl_DrawRectPatch,
6858 IWineD3DDeviceImpl_DrawTriPatch,
6859 IWineD3DDeviceImpl_DeletePatch,
6860 IWineD3DDeviceImpl_ColorFill,
6861 IWineD3DDeviceImpl_UpdateTexture,
6862 IWineD3DDeviceImpl_UpdateSurface,
6863 IWineD3DDeviceImpl_GetFrontBufferData,
6864 /*** object tracking ***/
6865 IWineD3DDeviceImpl_EnumResources,
6866 IWineD3DDeviceImpl_GetSurfaceFromDC,
6867 IWineD3DDeviceImpl_AcquireFocusWindow,
6868 IWineD3DDeviceImpl_ReleaseFocusWindow,
6871 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6872 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6873 IWineD3DDeviceParent *device_parent)
6875 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6876 const struct fragment_pipeline *fragment_pipeline;
6877 struct shader_caps shader_caps;
6878 struct fragment_caps ffp_caps;
6879 WINED3DDISPLAYMODE mode;
6880 unsigned int i;
6881 HRESULT hr;
6883 device->lpVtbl = &IWineD3DDevice_Vtbl;
6884 device->ref = 1;
6885 device->wined3d = (IWineD3D *)wined3d;
6886 IWineD3D_AddRef(device->wined3d);
6887 device->adapter = wined3d->adapter_count ? adapter : NULL;
6888 device->device_parent = device_parent;
6889 list_init(&device->resources);
6890 list_init(&device->shaders);
6892 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6893 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6895 /* Get the initial screen setup for ddraw. */
6896 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6897 if (FAILED(hr))
6899 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6900 IWineD3D_Release(device->wined3d);
6901 return hr;
6903 device->ddraw_width = mode.Width;
6904 device->ddraw_height = mode.Height;
6905 device->ddraw_format = mode.Format;
6907 /* Save the creation parameters. */
6908 device->createParms.AdapterOrdinal = adapter_idx;
6909 device->createParms.DeviceType = device_type;
6910 device->createParms.hFocusWindow = focus_window;
6911 device->createParms.BehaviorFlags = flags;
6913 device->devType = device_type;
6914 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6916 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6917 device->shader_backend = adapter->shader_backend;
6919 if (device->shader_backend)
6921 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6922 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6923 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6924 device->vs_clipping = shader_caps.VSClipping;
6926 fragment_pipeline = adapter->fragment_pipe;
6927 device->frag_pipe = fragment_pipeline;
6928 if (fragment_pipeline)
6930 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6931 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6933 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6934 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6935 if (FAILED(hr))
6937 ERR("Failed to compile state table, hr %#x.\n", hr);
6938 IWineD3D_Release(device->wined3d);
6939 return hr;
6942 device->blitter = adapter->blitter;
6944 return WINED3D_OK;
6948 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6949 DWORD rep = This->StateTable[state].representative;
6950 struct wined3d_context *context;
6951 DWORD idx;
6952 BYTE shift;
6953 UINT i;
6955 for(i = 0; i < This->numContexts; i++) {
6956 context = This->contexts[i];
6957 if(isStateDirty(context, rep)) continue;
6959 context->dirtyArray[context->numDirtyEntries++] = rep;
6960 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6961 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6962 context->isStateDirty[idx] |= (1 << shift);
6966 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6968 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6969 *width = context->current_rt->pow2Width;
6970 *height = context->current_rt->pow2Height;
6973 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6975 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6976 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6977 * current context's drawable, which is the size of the back buffer of the swapchain
6978 * the active context belongs to. */
6979 *width = swapchain->presentParms.BackBufferWidth;
6980 *height = swapchain->presentParms.BackBufferHeight;
6983 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6984 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6986 if (device->filter_messages)
6988 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6989 window, message, wparam, lparam);
6990 return DefWindowProcW(window, message, wparam, lparam);
6993 if (message == WM_DESTROY)
6995 TRACE("unregister window %p.\n", window);
6996 wined3d_unregister_window(window);
6998 if (device->focus_window == window) device->focus_window = NULL;
6999 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7002 return CallWindowProcW(proc, window, message, wparam, lparam);