wined3d: Move index buffer state to wined3d_state.
[wine.git] / dlls / wined3d / device.c
blobad54e5827597eafd6fdcf833a41388e6a0441b80
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->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
226 buffer_object = 0;
227 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
234 if (fixup)
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->state.vertex_shader,
263 element->usage, element->usage_idx, &idx);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
293 stream_info->elements[idx].format = element->format;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->state.user_stream)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
319 if (!(map & 1)) continue;
321 element = &stream_info->elements[i];
322 buffer = This->stateBlock->state.streams[element->stream_idx].buffer;
323 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
325 /* If PreLoad dropped the buffer object, update the stream info. */
326 if (buffer->buffer_object != element->buffer_object)
328 element->buffer_object = 0;
329 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
332 if (buffer->query)
333 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
338 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
339 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
341 e->format = wined3d_get_format(gl_info, strided->format);
342 e->stride = strided->dwStride;
343 e->data = strided->lpData;
344 e->stream_idx = 0;
345 e->buffer_object = 0;
348 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
349 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
351 unsigned int i;
353 memset(stream_info, 0, sizeof(*stream_info));
355 if (strided->position.lpData)
356 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
357 if (strided->normal.lpData)
358 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
359 if (strided->diffuse.lpData)
360 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
361 if (strided->specular.lpData)
362 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
364 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
366 if (strided->texCoords[i].lpData)
367 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
368 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
371 stream_info->position_transformed = strided->position_transformed;
373 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
375 if (!stream_info->elements[i].format) continue;
377 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
378 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
380 stream_info->swizzle_map |= 1 << i;
382 stream_info->use_map |= 1 << i;
386 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
388 TRACE("Strided Data:\n");
389 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
406 /* Context activation is done by the caller. */
407 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
409 struct wined3d_stream_info *stream_info = &device->strided_streams;
410 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
411 BOOL vs = stateblock->state.vertex_shader && device->vs_selected_mode != SHADER_NONE;
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, vs, stream_info, &fixup);
427 if (vs && !stream_info->position_transformed)
429 if (stateblock->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 unsigned int i;
471 if (use_vs(stateblock))
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (stateblock->state.vertex_shader->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
480 if (use_ps(stateblock))
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (stateblock->state.pixel_shader->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(stateblock, i);
488 else
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
494 if (ffu_map & 1)
495 device_preload_texture(stateblock, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
509 if (!new_array)
511 ERR("Failed to grow the context array.\n");
512 return FALSE;
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
517 return TRUE;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
523 BOOL found = FALSE;
524 UINT i;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
532 found = TRUE;
533 break;
537 if (!found)
539 ERR("Context %p doesn't exist in context array.\n", context);
540 return;
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
547 return;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
552 if (!new_array)
554 ERR("Failed to shrink context array. Oh well.\n");
555 return;
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
596 return FALSE;
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
602 return FALSE;
604 return TRUE;
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(&current_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
616 else
617 SetRectEmpty(&current_rect);
619 IntersectRect(&r, draw_rect, &current_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
624 return;
627 if (EqualRect(&r, &current_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
631 if (!clear_rect)
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
635 return;
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 return;
647 /* Full load. */
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
663 unsigned int i;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
682 if (!context->valid)
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
686 return WINED3D_OK;
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
693 ENTER_GL();
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
703 glStencilMask(~0U);
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
716 LEAVE_GL();
717 device_switch_onscreen_ds(device, context, depth_stencil);
718 ENTER_GL();
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
725 glClearDepth(depth);
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
747 if (!clear_rect)
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
754 else
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
760 glClear(clear_mask);
761 checkGLcall("glClear");
763 else
765 RECT current_rect;
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(&current_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
783 continue;
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
791 else
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
798 glClear(clear_mask);
799 checkGLcall("glClear");
803 LEAVE_GL();
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
811 return WINED3D_OK;
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
827 *object = iface;
828 return S_OK;
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
833 *object = NULL;
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
842 return refCount;
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
851 if (!refCount) {
852 UINT i;
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
884 This = NULL;
886 return refCount;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
894 HRESULT hr;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
909 if (FAILED(hr))
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 return hr;
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
921 return WINED3D_OK;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
930 HRESULT hr;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
946 if (!object)
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
955 if (FAILED(hr))
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
959 return hr;
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
974 HRESULT hr;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
980 if (!object)
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
989 parent, parent_ops);
990 if (FAILED(hr))
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
994 return hr;
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1001 return WINED3D_OK;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1009 HRESULT hr;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1012 if(!object)
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1019 if (FAILED(hr))
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1023 return hr;
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1039 HRESULT hr;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054 if (!object)
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1062 if (FAILED(hr))
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1066 return hr;
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1073 return hr;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1085 if (!object)
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1096 return WINED3D_OK;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1105 HRESULT hr;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1112 if (!object)
1114 ERR("Out of memory\n");
1115 *ppTexture = NULL;
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1120 if (FAILED(hr))
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1124 *ppTexture = NULL;
1125 return hr;
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1132 return WINED3D_OK;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1141 HRESULT hr;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1147 if (!object)
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1155 if (FAILED(hr))
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1160 return hr;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1166 return WINED3D_OK;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1175 HRESULT hr;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1181 if (!object)
1183 ERR("Out of memory\n");
1184 *ppVolume = NULL;
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1189 if (FAILED(hr))
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1193 return hr;
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1199 return WINED3D_OK;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1208 HRESULT hr;
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1211 if (!object)
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1219 if (FAILED(hr))
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1224 return hr;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1230 return WINED3D_OK;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1238 HRESULT hr;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1243 if (!object)
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1250 if (FAILED(hr))
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1254 return hr;
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1260 return WINED3D_OK;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1270 HRESULT hr;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1276 if (!object)
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1283 if (FAILED(hr))
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1287 return hr;
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1293 return WINED3D_OK;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1312 return WINED3D_OK;
1313 } else {
1314 TRACE("Swapchain out of range\n");
1315 *pSwapChain = NULL;
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1326 HRESULT hr;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1332 if(!object)
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1339 if (FAILED(hr))
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1343 return hr;
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1349 return WINED3D_OK;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1356 UINT offset;
1357 UINT idx;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1378 ++state->idx;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1399 unsigned int size;
1400 unsigned int idx;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1411 state.offset = 0;
1412 state.idx = 0;
1414 if (has_pos)
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1420 else
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1428 else
1430 switch (num_blends)
1432 case 1:
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 break;
1435 case 2:
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 break;
1438 case 3:
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 break;
1441 case 4:
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 default:
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1450 if (has_blend_idx)
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1457 else
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1472 break;
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1475 break;
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 break;
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1485 *ppVertexElements = state.elements;
1486 return size;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1495 unsigned int size;
1496 DWORD hr;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1505 return hr;
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1515 HRESULT hr;
1517 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1518 if (!object)
1520 ERR("Failed to allocate shader memory.\n");
1521 return E_OUTOFMEMORY;
1524 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1525 if (FAILED(hr))
1527 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1528 HeapFree(GetProcessHeap(), 0, object);
1529 return hr;
1532 TRACE("Created vertex shader %p.\n", object);
1533 *ppVertexShader = (IWineD3DVertexShader *)object;
1535 return WINED3D_OK;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1539 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1540 void *parent, const struct wined3d_parent_ops *parent_ops,
1541 IWineD3DGeometryShader **shader)
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 struct wined3d_geometryshader *object;
1545 HRESULT hr;
1547 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1548 if (!object)
1550 ERR("Failed to allocate shader memory.\n");
1551 return E_OUTOFMEMORY;
1554 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1555 if (FAILED(hr))
1557 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1558 HeapFree(GetProcessHeap(), 0, object);
1559 return hr;
1562 TRACE("Created geometry shader %p.\n", object);
1563 *shader = (IWineD3DGeometryShader *)object;
1565 return WINED3D_OK;
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1569 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1570 void *parent, const struct wined3d_parent_ops *parent_ops,
1571 IWineD3DPixelShader **ppPixelShader)
1573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1574 IWineD3DPixelShaderImpl *object;
1575 HRESULT hr;
1577 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1578 if (!object)
1580 ERR("Failed to allocate shader memory.\n");
1581 return E_OUTOFMEMORY;
1584 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1585 if (FAILED(hr))
1587 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1588 HeapFree(GetProcessHeap(), 0, object);
1589 return hr;
1592 TRACE("Created pixel shader %p.\n", object);
1593 *ppPixelShader = (IWineD3DPixelShader *)object;
1595 return WINED3D_OK;
1598 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1599 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1602 IWineD3DPaletteImpl *object;
1603 HRESULT hr;
1605 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1606 iface, Flags, PalEnt, Palette, parent);
1608 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1609 if (!object)
1611 ERR("Failed to allocate palette memory.\n");
1612 return E_OUTOFMEMORY;
1615 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1616 if (FAILED(hr))
1618 WARN("Failed to initialize palette, hr %#x.\n", hr);
1619 HeapFree(GetProcessHeap(), 0, object);
1620 return hr;
1623 TRACE("Created palette %p.\n", object);
1624 *Palette = (IWineD3DPalette *)object;
1626 return WINED3D_OK;
1629 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1630 HBITMAP hbm;
1631 BITMAP bm;
1632 HRESULT hr;
1633 HDC dcb = NULL, dcs = NULL;
1634 WINEDDCOLORKEY colorkey;
1636 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1637 if(hbm)
1639 GetObjectA(hbm, sizeof(BITMAP), &bm);
1640 dcb = CreateCompatibleDC(NULL);
1641 if(!dcb) goto out;
1642 SelectObject(dcb, hbm);
1644 else
1646 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1647 * couldn't be loaded
1649 memset(&bm, 0, sizeof(bm));
1650 bm.bmWidth = 32;
1651 bm.bmHeight = 32;
1654 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1655 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1656 &wined3d_null_parent_ops, &This->logo_surface);
1657 if (FAILED(hr))
1659 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1660 goto out;
1663 if(dcb) {
1664 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1665 if(FAILED(hr)) goto out;
1666 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1667 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1669 colorkey.dwColorSpaceLowValue = 0;
1670 colorkey.dwColorSpaceHighValue = 0;
1671 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1673 else
1675 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1676 /* Fill the surface with a white color to show that wined3d is there */
1677 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1680 out:
1681 if (dcb) DeleteDC(dcb);
1682 if (hbm) DeleteObject(hbm);
1685 /* Context activation is done by the caller. */
1686 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1688 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1689 unsigned int i;
1690 /* Under DirectX you can have texture stage operations even if no texture is
1691 bound, whereas opengl will only do texture operations when a valid texture is
1692 bound. We emulate this by creating dummy textures and binding them to each
1693 texture stage, but disable all stages by default. Hence if a stage is enabled
1694 then the default texture will kick in until replaced by a SetTexture call */
1695 ENTER_GL();
1697 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1699 /* The dummy texture does not have client storage backing */
1700 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1701 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1704 for (i = 0; i < gl_info->limits.textures; ++i)
1706 GLubyte white = 255;
1708 /* Make appropriate texture active */
1709 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1710 checkGLcall("glActiveTextureARB");
1712 /* Generate an opengl texture name */
1713 glGenTextures(1, &This->dummyTextureName[i]);
1714 checkGLcall("glGenTextures");
1715 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1717 /* Generate a dummy 2d texture (not using 1d because they cause many
1718 * DRI drivers fall back to sw) */
1719 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1720 checkGLcall("glBindTexture");
1722 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1723 checkGLcall("glTexImage2D");
1726 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1728 /* Reenable because if supported it is enabled by default */
1729 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1730 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1733 LEAVE_GL();
1736 /* Context activation is done by the caller. */
1737 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1739 ENTER_GL();
1740 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1741 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1742 LEAVE_GL();
1744 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1747 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1749 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1751 if (!wined3d_register_window(window, device))
1753 ERR("Failed to register window %p.\n", window);
1754 return E_FAIL;
1757 device->focus_window = window;
1758 SetForegroundWindow(window);
1760 return WINED3D_OK;
1763 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1765 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1767 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1768 device->focus_window = NULL;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1772 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1776 IWineD3DSwapChainImpl *swapchain = NULL;
1777 struct wined3d_context *context;
1778 HRESULT hr;
1779 DWORD state;
1780 unsigned int i;
1782 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1784 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1785 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1787 TRACE("(%p) : Creating stateblock\n", This);
1788 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1789 if (FAILED(hr))
1791 WARN("Failed to create stateblock\n");
1792 goto err_out;
1794 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1795 This->updateStateBlock = This->stateBlock;
1796 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1798 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1799 sizeof(*This->render_targets) * gl_info->limits.buffers);
1801 This->NumberOfPalettes = 1;
1802 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1803 if (!This->palettes || !This->render_targets)
1805 ERR("Out of memory!\n");
1806 hr = E_OUTOFMEMORY;
1807 goto err_out;
1809 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1810 if(!This->palettes[0]) {
1811 ERR("Out of memory!\n");
1812 hr = E_OUTOFMEMORY;
1813 goto err_out;
1815 for (i = 0; i < 256; ++i) {
1816 This->palettes[0][i].peRed = 0xFF;
1817 This->palettes[0][i].peGreen = 0xFF;
1818 This->palettes[0][i].peBlue = 0xFF;
1819 This->palettes[0][i].peFlags = 0xFF;
1821 This->currentPalette = 0;
1823 /* Initialize the texture unit mapping to a 1:1 mapping */
1824 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1826 if (state < gl_info->limits.fragment_samplers)
1828 This->texUnitMap[state] = state;
1829 This->rev_tex_unit_map[state] = state;
1830 } else {
1831 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1832 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1836 /* Setup the implicit swapchain. This also initializes a context. */
1837 TRACE("Creating implicit swapchain\n");
1838 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1839 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1840 if (FAILED(hr))
1842 WARN("Failed to create implicit swapchain\n");
1843 goto err_out;
1846 This->NumberOfSwapChains = 1;
1847 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1848 if(!This->swapchains) {
1849 ERR("Out of memory!\n");
1850 goto err_out;
1852 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1854 if (swapchain->back_buffers && swapchain->back_buffers[0])
1856 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1857 This->render_targets[0] = swapchain->back_buffers[0];
1859 else
1861 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1862 This->render_targets[0] = swapchain->front_buffer;
1864 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1866 /* Depth Stencil support */
1867 This->depth_stencil = This->auto_depth_stencil;
1868 if (This->depth_stencil)
1869 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1871 hr = This->shader_backend->shader_alloc_private(iface);
1872 if(FAILED(hr)) {
1873 TRACE("Shader private data couldn't be allocated\n");
1874 goto err_out;
1876 hr = This->frag_pipe->alloc_private(iface);
1877 if(FAILED(hr)) {
1878 TRACE("Fragment pipeline private data couldn't be allocated\n");
1879 goto err_out;
1881 hr = This->blitter->alloc_private(iface);
1882 if(FAILED(hr)) {
1883 TRACE("Blitter private data couldn't be allocated\n");
1884 goto err_out;
1887 /* Set up some starting GL setup */
1889 /* Setup all the devices defaults */
1890 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1892 context = context_acquire(This, swapchain->front_buffer);
1894 create_dummy_textures(This);
1896 ENTER_GL();
1898 /* Initialize the current view state */
1899 This->view_ident = 1;
1900 This->contexts[0]->last_was_rhw = 0;
1901 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1902 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1904 switch(wined3d_settings.offscreen_rendering_mode) {
1905 case ORM_FBO:
1906 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1907 break;
1909 case ORM_BACKBUFFER:
1911 if (context_get_current()->aux_buffers > 0)
1913 TRACE("Using auxilliary buffer for offscreen rendering\n");
1914 This->offscreenBuffer = GL_AUX0;
1915 } else {
1916 TRACE("Using back buffer for offscreen rendering\n");
1917 This->offscreenBuffer = GL_BACK;
1922 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1923 LEAVE_GL();
1925 context_release(context);
1927 /* Clear the screen */
1928 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1929 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1930 0x00, 1.0f, 0);
1932 This->d3d_initialized = TRUE;
1934 if(wined3d_settings.logo) {
1935 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1937 This->highest_dirty_ps_const = 0;
1938 This->highest_dirty_vs_const = 0;
1939 return WINED3D_OK;
1941 err_out:
1942 HeapFree(GetProcessHeap(), 0, This->render_targets);
1943 HeapFree(GetProcessHeap(), 0, This->swapchains);
1944 This->NumberOfSwapChains = 0;
1945 if(This->palettes) {
1946 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1947 HeapFree(GetProcessHeap(), 0, This->palettes);
1949 This->NumberOfPalettes = 0;
1950 if(swapchain) {
1951 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1953 if(This->stateBlock) {
1954 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1955 This->stateBlock = NULL;
1957 if (This->blit_priv) {
1958 This->blitter->free_private(iface);
1960 if (This->fragment_priv) {
1961 This->frag_pipe->free_private(iface);
1963 if (This->shader_priv) {
1964 This->shader_backend->shader_free_private(iface);
1966 return hr;
1969 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1970 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1973 IWineD3DSwapChainImpl *swapchain = NULL;
1974 HRESULT hr;
1976 /* Setup the implicit swapchain */
1977 TRACE("Creating implicit swapchain\n");
1978 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1979 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1980 if (FAILED(hr))
1982 WARN("Failed to create implicit swapchain\n");
1983 goto err_out;
1986 This->NumberOfSwapChains = 1;
1987 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1988 if(!This->swapchains) {
1989 ERR("Out of memory!\n");
1990 goto err_out;
1992 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1993 return WINED3D_OK;
1995 err_out:
1996 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1997 return hr;
2000 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2002 IWineD3DResource_UnLoad(resource);
2003 IWineD3DResource_Release(resource);
2004 return WINED3D_OK;
2007 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2008 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2011 const struct wined3d_gl_info *gl_info;
2012 struct wined3d_context *context;
2013 int sampler;
2014 UINT i;
2015 TRACE("(%p)\n", This);
2017 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2019 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2020 * it was created. Thus make sure a context is active for the glDelete* calls
2022 context = context_acquire(This, NULL);
2023 gl_info = context->gl_info;
2025 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2027 /* Unload resources */
2028 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2030 TRACE("Deleting high order patches\n");
2031 for(i = 0; i < PATCHMAP_SIZE; i++) {
2032 struct list *e1, *e2;
2033 struct WineD3DRectPatch *patch;
2034 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2035 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2036 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2040 /* Delete the mouse cursor texture */
2041 if(This->cursorTexture) {
2042 ENTER_GL();
2043 glDeleteTextures(1, &This->cursorTexture);
2044 LEAVE_GL();
2045 This->cursorTexture = 0;
2048 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2049 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2051 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2052 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2055 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2056 * private data, it might contain opengl pointers
2058 if(This->depth_blt_texture) {
2059 ENTER_GL();
2060 glDeleteTextures(1, &This->depth_blt_texture);
2061 LEAVE_GL();
2062 This->depth_blt_texture = 0;
2064 if (This->depth_blt_rb) {
2065 ENTER_GL();
2066 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2067 LEAVE_GL();
2068 This->depth_blt_rb = 0;
2069 This->depth_blt_rb_w = 0;
2070 This->depth_blt_rb_h = 0;
2073 /* Release the update stateblock */
2074 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2075 if(This->updateStateBlock != This->stateBlock)
2076 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2078 This->updateStateBlock = NULL;
2080 { /* because were not doing proper internal refcounts releasing the primary state block
2081 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2082 to set this->stateBlock = NULL; first */
2083 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2084 This->stateBlock = NULL;
2086 /* Release the stateblock */
2087 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2088 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2092 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2093 This->blitter->free_private(iface);
2094 This->frag_pipe->free_private(iface);
2095 This->shader_backend->shader_free_private(iface);
2097 /* Release the buffers (with sanity checks)*/
2098 if (This->onscreen_depth_stencil)
2100 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2101 This->onscreen_depth_stencil = NULL;
2104 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2105 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2107 if (This->auto_depth_stencil != This->depth_stencil)
2108 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2110 This->depth_stencil = NULL;
2112 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2113 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2115 TRACE("Setting rendertarget to NULL\n");
2116 This->render_targets[0] = NULL;
2118 if (This->auto_depth_stencil)
2120 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2122 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2124 This->auto_depth_stencil = NULL;
2127 context_release(context);
2129 for(i=0; i < This->NumberOfSwapChains; i++) {
2130 TRACE("Releasing the implicit swapchain %d\n", i);
2131 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2132 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2136 HeapFree(GetProcessHeap(), 0, This->swapchains);
2137 This->swapchains = NULL;
2138 This->NumberOfSwapChains = 0;
2140 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2141 HeapFree(GetProcessHeap(), 0, This->palettes);
2142 This->palettes = NULL;
2143 This->NumberOfPalettes = 0;
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 This->render_targets = NULL;
2148 This->d3d_initialized = FALSE;
2150 return WINED3D_OK;
2153 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2155 unsigned int i;
2157 for(i=0; i < This->NumberOfSwapChains; i++) {
2158 TRACE("Releasing the implicit swapchain %d\n", i);
2159 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2160 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2164 HeapFree(GetProcessHeap(), 0, This->swapchains);
2165 This->swapchains = NULL;
2166 This->NumberOfSwapChains = 0;
2167 return WINED3D_OK;
2170 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2171 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2172 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2174 * There is no way to deactivate thread safety once it is enabled.
2176 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2179 /*For now just store the flag(needed in case of ddraw) */
2180 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2183 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2184 const WINED3DDISPLAYMODE* pMode) {
2185 DEVMODEW devmode;
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2188 LONG ret;
2189 RECT clip_rc;
2191 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2193 /* Resize the screen even without a window:
2194 * The app could have unset it with SetCooperativeLevel, but not called
2195 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2196 * but we don't have any hwnd
2199 memset(&devmode, 0, sizeof(devmode));
2200 devmode.dmSize = sizeof(devmode);
2201 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2202 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2203 devmode.dmPelsWidth = pMode->Width;
2204 devmode.dmPelsHeight = pMode->Height;
2206 devmode.dmDisplayFrequency = pMode->RefreshRate;
2207 if (pMode->RefreshRate)
2208 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2210 /* Only change the mode if necessary */
2211 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2212 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2213 return WINED3D_OK;
2215 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2216 if (ret != DISP_CHANGE_SUCCESSFUL)
2218 if (devmode.dmDisplayFrequency)
2220 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2221 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2222 devmode.dmDisplayFrequency = 0;
2223 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2225 if(ret != DISP_CHANGE_SUCCESSFUL) {
2226 return WINED3DERR_NOTAVAILABLE;
2230 /* Store the new values */
2231 This->ddraw_width = pMode->Width;
2232 This->ddraw_height = pMode->Height;
2233 This->ddraw_format = pMode->Format;
2235 /* And finally clip mouse to our screen */
2236 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2237 ClipCursor(&clip_rc);
2239 return WINED3D_OK;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 *ppD3D = This->wined3d;
2245 TRACE("Returning %p.\n", *ppD3D);
2246 IWineD3D_AddRef(*ppD3D);
2247 return WINED3D_OK;
2250 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2254 (This->adapter->TextureRam/(1024*1024)),
2255 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2256 /* return simulated texture memory left */
2257 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2260 /*****
2261 * Get / Set Stream Source
2262 *****/
2263 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2264 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2267 struct wined3d_stream_state *stream;
2268 IWineD3DBuffer *oldSrc;
2270 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2271 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2273 if (StreamNumber >= MAX_STREAMS) {
2274 WARN("Stream out of range %d\n", StreamNumber);
2275 return WINED3DERR_INVALIDCALL;
2276 } else if(OffsetInBytes & 0x3) {
2277 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2278 return WINED3DERR_INVALIDCALL;
2281 stream = &This->updateStateBlock->state.streams[StreamNumber];
2282 oldSrc = (IWineD3DBuffer *)stream->buffer;
2284 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2286 if (oldSrc == pStreamData
2287 && stream->stride == Stride
2288 && stream->offset == OffsetInBytes)
2290 TRACE("Application is setting the old values over, nothing to do\n");
2291 return WINED3D_OK;
2294 stream->buffer = (struct wined3d_buffer *)pStreamData;
2295 if (pStreamData)
2297 stream->stride = Stride;
2298 stream->offset = OffsetInBytes;
2301 /* Handle recording of state blocks */
2302 if (This->isRecordingState) {
2303 TRACE("Recording... not performing anything\n");
2304 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2305 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2306 return WINED3D_OK;
2309 if (pStreamData)
2311 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2312 IWineD3DBuffer_AddRef(pStreamData);
2314 if (oldSrc)
2316 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2317 IWineD3DBuffer_Release(oldSrc);
2320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2322 return WINED3D_OK;
2325 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2326 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 struct wined3d_stream_state *stream;
2331 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2332 iface, StreamNumber, pStream, pOffset, pStride);
2334 if (StreamNumber >= MAX_STREAMS)
2336 WARN("Stream out of range %d\n", StreamNumber);
2337 return WINED3DERR_INVALIDCALL;
2340 stream = &This->stateBlock->state.streams[StreamNumber];
2341 *pStream = (IWineD3DBuffer *)stream->buffer;
2342 *pStride = stream->stride;
2343 if (pOffset) *pOffset = stream->offset;
2345 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2347 return WINED3D_OK;
2350 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 struct wined3d_stream_state *stream;
2353 UINT oldFlags, oldFreq;
2355 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2357 /* Verify input at least in d3d9 this is invalid. */
2358 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2360 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2361 return WINED3DERR_INVALIDCALL;
2363 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2365 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2368 if (!Divider)
2370 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2374 stream = &This->updateStateBlock->state.streams[StreamNumber];
2375 oldFlags = stream->flags;
2376 oldFreq = stream->frequency;
2378 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2379 stream->frequency = Divider & 0x7FFFFF;
2381 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2383 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2386 return WINED3D_OK;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2393 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2395 stream = &This->updateStateBlock->state.streams[StreamNumber];
2396 *Divider = stream->flags | stream->frequency;
2398 TRACE("Returning %#x.\n", *Divider);
2400 return WINED3D_OK;
2403 /*****
2404 * Get / Set & Multiply Transform
2405 *****/
2406 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 /* Most of this routine, comments included copied from ddraw tree initially: */
2410 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2412 /* Handle recording of state blocks */
2413 if (This->isRecordingState) {
2414 TRACE("Recording... not performing anything\n");
2415 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2416 This->updateStateBlock->state.transforms[d3dts] = *lpmatrix;
2417 return WINED3D_OK;
2421 * If the new matrix is the same as the current one,
2422 * we cut off any further processing. this seems to be a reasonable
2423 * optimization because as was noticed, some apps (warcraft3 for example)
2424 * tend towards setting the same matrix repeatedly for some reason.
2426 * From here on we assume that the new matrix is different, wherever it matters.
2428 if (!memcmp(&This->stateBlock->state.transforms[d3dts].u.m[0][0], lpmatrix, sizeof(*lpmatrix)))
2430 TRACE("The app is setting the same matrix over again\n");
2431 return WINED3D_OK;
2433 else
2435 conv_mat(lpmatrix, &This->stateBlock->state.transforms[d3dts].u.m[0][0]);
2439 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2440 where ViewMat = Camera space, WorldMat = world space.
2442 In OpenGL, camera and world space is combined into GL_MODELVIEW
2443 matrix. The Projection matrix stay projection matrix.
2446 /* Capture the times we can just ignore the change for now */
2447 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2448 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2449 /* Handled by the state manager */
2452 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2455 return WINED3D_OK;
2459 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface,
2460 WINED3DTRANSFORMSTATETYPE state, WINED3DMATRIX *matrix)
2462 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
2464 TRACE("iface %p, state %s, matrix %p.\n", iface, debug_d3dtstype(state), matrix);
2466 *matrix = device->stateBlock->state.transforms[state];
2468 return WINED3D_OK;
2471 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2472 const WINED3DMATRIX *mat = NULL;
2473 WINED3DMATRIX temp;
2475 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2476 * below means it will be recorded in a state block change, but it
2477 * works regardless where it is recorded.
2478 * If this is found to be wrong, change to StateBlock.
2480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2483 if (State <= HIGHEST_TRANSFORMSTATE)
2485 mat = &This->updateStateBlock->state.transforms[State];
2487 else
2489 FIXME("Unhandled transform state!!\n");
2492 multiply_matrix(&temp, mat, pMatrix);
2494 /* Apply change via set transform - will reapply to eg. lights this way */
2495 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2498 /*****
2499 * Get / Set Light
2500 *****/
2501 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2502 you can reference any indexes you want as long as that number max are enabled at any
2503 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2504 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2505 but when recording, just build a chain pretty much of commands to be replayed. */
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2508 float rho;
2509 struct wined3d_light_info *object = NULL;
2510 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2511 struct list *e;
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2516 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2517 * the gl driver.
2519 if(!pLight) {
2520 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2521 return WINED3DERR_INVALIDCALL;
2524 switch(pLight->Type) {
2525 case WINED3DLIGHT_POINT:
2526 case WINED3DLIGHT_SPOT:
2527 case WINED3DLIGHT_PARALLELPOINT:
2528 case WINED3DLIGHT_GLSPOT:
2529 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2530 * most wanted
2532 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2534 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2535 return WINED3DERR_INVALIDCALL;
2537 break;
2539 case WINED3DLIGHT_DIRECTIONAL:
2540 /* Ignores attenuation */
2541 break;
2543 default:
2544 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2545 return WINED3DERR_INVALIDCALL;
2548 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2550 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2551 if(object->OriginalIndex == Index) break;
2552 object = NULL;
2555 if(!object) {
2556 TRACE("Adding new light\n");
2557 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2558 if(!object) {
2559 ERR("Out of memory error when allocating a light\n");
2560 return E_OUTOFMEMORY;
2562 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2563 object->glIndex = -1;
2564 object->OriginalIndex = Index;
2567 /* Initialize the object */
2568 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,
2569 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2570 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2571 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2572 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2573 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2574 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2576 /* Save away the information */
2577 object->OriginalParms = *pLight;
2579 switch (pLight->Type) {
2580 case WINED3DLIGHT_POINT:
2581 /* Position */
2582 object->lightPosn[0] = pLight->Position.x;
2583 object->lightPosn[1] = pLight->Position.y;
2584 object->lightPosn[2] = pLight->Position.z;
2585 object->lightPosn[3] = 1.0f;
2586 object->cutoff = 180.0f;
2587 /* FIXME: Range */
2588 break;
2590 case WINED3DLIGHT_DIRECTIONAL:
2591 /* Direction */
2592 object->lightPosn[0] = -pLight->Direction.x;
2593 object->lightPosn[1] = -pLight->Direction.y;
2594 object->lightPosn[2] = -pLight->Direction.z;
2595 object->lightPosn[3] = 0.0f;
2596 object->exponent = 0.0f;
2597 object->cutoff = 180.0f;
2598 break;
2600 case WINED3DLIGHT_SPOT:
2601 /* Position */
2602 object->lightPosn[0] = pLight->Position.x;
2603 object->lightPosn[1] = pLight->Position.y;
2604 object->lightPosn[2] = pLight->Position.z;
2605 object->lightPosn[3] = 1.0f;
2607 /* Direction */
2608 object->lightDirn[0] = pLight->Direction.x;
2609 object->lightDirn[1] = pLight->Direction.y;
2610 object->lightDirn[2] = pLight->Direction.z;
2611 object->lightDirn[3] = 1.0f;
2614 * opengl-ish and d3d-ish spot lights use too different models for the
2615 * light "intensity" as a function of the angle towards the main light direction,
2616 * so we only can approximate very roughly.
2617 * however spot lights are rather rarely used in games (if ever used at all).
2618 * furthermore if still used, probably nobody pays attention to such details.
2620 if (!pLight->Falloff)
2622 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2623 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2624 * will always be 1.0 for both of them, and we don't have to care for the
2625 * rest of the rather complex calculation
2627 object->exponent = 0.0f;
2628 } else {
2629 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2630 if (rho < 0.0001f) rho = 0.0001f;
2631 object->exponent = -0.3f/logf(cosf(rho/2));
2633 if (object->exponent > 128.0f)
2635 object->exponent = 128.0f;
2637 object->cutoff = (float) (pLight->Phi*90/M_PI);
2639 /* FIXME: Range */
2640 break;
2642 default:
2643 FIXME("Unrecognized light type %d\n", pLight->Type);
2646 /* Update the live definitions if the light is currently assigned a glIndex */
2647 if (object->glIndex != -1 && !This->isRecordingState) {
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2650 return WINED3D_OK;
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2655 struct wined3d_light_info *lightInfo = NULL;
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2657 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2658 struct list *e;
2659 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2661 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2663 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2664 if(lightInfo->OriginalIndex == Index) break;
2665 lightInfo = NULL;
2668 if (!lightInfo)
2670 TRACE("Light information requested but light not defined\n");
2671 return WINED3DERR_INVALIDCALL;
2674 *pLight = lightInfo->OriginalParms;
2675 return WINED3D_OK;
2678 /*****
2679 * Get / Set Light Enable
2680 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2681 *****/
2682 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2684 struct wined3d_light_info *lightInfo = NULL;
2685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2687 struct list *e;
2688 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2690 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2692 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2693 if(lightInfo->OriginalIndex == Index) break;
2694 lightInfo = NULL;
2696 TRACE("Found light: %p\n", lightInfo);
2698 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2699 if (!lightInfo)
2701 TRACE("Light enabled requested but light not defined, so defining one!\n");
2702 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2704 /* Search for it again! Should be fairly quick as near head of list */
2705 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2707 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2708 if(lightInfo->OriginalIndex == Index) break;
2709 lightInfo = NULL;
2711 if (!lightInfo)
2713 FIXME("Adding default lights has failed dismally\n");
2714 return WINED3DERR_INVALIDCALL;
2718 if(!Enable) {
2719 if(lightInfo->glIndex != -1) {
2720 if(!This->isRecordingState) {
2721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2724 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2725 lightInfo->glIndex = -1;
2726 } else {
2727 TRACE("Light already disabled, nothing to do\n");
2729 lightInfo->enabled = FALSE;
2730 } else {
2731 lightInfo->enabled = TRUE;
2732 if (lightInfo->glIndex != -1) {
2733 /* nop */
2734 TRACE("Nothing to do as light was enabled\n");
2735 } else {
2736 int i;
2737 /* Find a free gl light */
2738 for (i = 0; i < This->maxConcurrentLights; ++i)
2740 if (!This->updateStateBlock->activeLights[i])
2742 This->updateStateBlock->activeLights[i] = lightInfo;
2743 lightInfo->glIndex = i;
2744 break;
2747 if(lightInfo->glIndex == -1) {
2748 /* Our tests show that Windows returns D3D_OK in this situation, even with
2749 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2750 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2751 * as well for those lights.
2753 * TODO: Test how this affects rendering
2755 WARN("Too many concurrently active lights\n");
2756 return WINED3D_OK;
2759 /* i == lightInfo->glIndex */
2760 if(!This->isRecordingState) {
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2766 return WINED3D_OK;
2769 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2771 struct wined3d_light_info *lightInfo = NULL;
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 struct list *e;
2774 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2775 TRACE("(%p) : for idx(%d)\n", This, Index);
2777 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2779 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2780 if(lightInfo->OriginalIndex == Index) break;
2781 lightInfo = NULL;
2784 if (!lightInfo)
2786 TRACE("Light enabled state requested but light not defined\n");
2787 return WINED3DERR_INVALIDCALL;
2789 /* true is 128 according to SetLightEnable */
2790 *pEnable = lightInfo->enabled ? 128 : 0;
2791 return WINED3D_OK;
2794 /*****
2795 * Get / Set Clip Planes
2796 *****/
2797 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2801 /* Validate Index */
2802 if (Index >= This->adapter->gl_info.limits.clipplanes)
2804 TRACE("Application has requested clipplane this device doesn't support\n");
2805 return WINED3DERR_INVALIDCALL;
2808 This->updateStateBlock->changed.clipplane |= 1 << Index;
2810 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2811 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2812 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2813 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2814 TRACE("Application is setting old values over, nothing to do\n");
2815 return WINED3D_OK;
2818 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2819 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2820 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2821 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2823 /* Handle recording of state blocks */
2824 if (This->isRecordingState) {
2825 TRACE("Recording... not performing anything\n");
2826 return WINED3D_OK;
2829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2831 return WINED3D_OK;
2834 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2836 TRACE("(%p) : for idx %d\n", This, Index);
2838 /* Validate Index */
2839 if (Index >= This->adapter->gl_info.limits.clipplanes)
2841 TRACE("Application has requested clipplane this device doesn't support\n");
2842 return WINED3DERR_INVALIDCALL;
2845 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2846 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2847 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2848 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2849 return WINED3D_OK;
2852 /*****
2853 * Get / Set Clip Plane Status
2854 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2855 *****/
2856 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 FIXME("(%p) : stub\n", This);
2860 if (!pClipStatus)
2861 return WINED3DERR_INVALIDCALL;
2863 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2864 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2865 return WINED3D_OK;
2868 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 FIXME("(%p) : stub\n", This);
2872 if (!pClipStatus)
2873 return WINED3DERR_INVALIDCALL;
2875 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2876 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2877 return WINED3D_OK;
2880 /*****
2881 * Get / Set Material
2882 *****/
2883 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 This->updateStateBlock->changed.material = TRUE;
2887 This->updateStateBlock->state.material = *pMaterial;
2889 /* Handle recording of state blocks */
2890 if (This->isRecordingState) {
2891 TRACE("Recording... not performing anything\n");
2892 return WINED3D_OK;
2895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2896 return WINED3D_OK;
2899 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 *pMaterial = This->updateStateBlock->state.material;
2902 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2903 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2904 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2905 pMaterial->Ambient.b, pMaterial->Ambient.a);
2906 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2907 pMaterial->Specular.b, pMaterial->Specular.a);
2908 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2909 pMaterial->Emissive.b, pMaterial->Emissive.a);
2910 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2912 return WINED3D_OK;
2915 /*****
2916 * Get / Set Indices
2917 *****/
2918 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2919 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 IWineD3DBuffer *oldIdxs;
2924 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2925 oldIdxs = (IWineD3DBuffer *)This->updateStateBlock->state.index_buffer;
2927 This->updateStateBlock->changed.indices = TRUE;
2928 This->updateStateBlock->state.index_buffer = (struct wined3d_buffer *)pIndexData;
2929 This->updateStateBlock->state.index_format = fmt;
2931 /* Handle recording of state blocks */
2932 if (This->isRecordingState) {
2933 TRACE("Recording... not performing anything\n");
2934 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2935 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2936 return WINED3D_OK;
2939 if(oldIdxs != pIndexData) {
2940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2941 if(pIndexData) {
2942 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2943 IWineD3DBuffer_AddRef(pIndexData);
2945 if(oldIdxs) {
2946 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2947 IWineD3DBuffer_Release(oldIdxs);
2951 return WINED3D_OK;
2954 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 *ppIndexData = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
2960 /* up ref count on ppindexdata */
2961 if (*ppIndexData) {
2962 IWineD3DBuffer_AddRef(*ppIndexData);
2963 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2964 }else{
2965 TRACE("(%p) No index data set\n", This);
2967 TRACE("Returning %p\n", *ppIndexData);
2969 return WINED3D_OK;
2972 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2973 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 TRACE("(%p)->(%d)\n", This, BaseIndex);
2977 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2978 TRACE("Application is setting the old value over, nothing to do\n");
2979 return WINED3D_OK;
2982 This->updateStateBlock->baseVertexIndex = BaseIndex;
2984 if (This->isRecordingState) {
2985 TRACE("Recording... not performing anything\n");
2986 return WINED3D_OK;
2988 /* The base vertex index affects the stream sources */
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2990 return WINED3D_OK;
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 TRACE("(%p) : base_index %p\n", This, base_index);
2997 *base_index = This->stateBlock->baseVertexIndex;
2999 TRACE("Returning %u\n", *base_index);
3001 return WINED3D_OK;
3004 /*****
3005 * Get / Set Viewports
3006 *****/
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 TRACE("(%p)\n", This);
3011 This->updateStateBlock->changed.viewport = TRUE;
3012 This->updateStateBlock->state.viewport = *pViewport;
3014 /* Handle recording of state blocks */
3015 if (This->isRecordingState) {
3016 TRACE("Recording... not performing anything\n");
3017 return WINED3D_OK;
3020 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3021 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3024 return WINED3D_OK;
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 TRACE("(%p)\n", This);
3031 *pViewport = This->stateBlock->state.viewport;
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3036 WINED3DRENDERSTATETYPE State, DWORD Value)
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 DWORD oldValue = This->stateBlock->state.render_states[State];
3041 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3043 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3044 This->updateStateBlock->state.render_states[State] = Value;
3046 /* Handle recording of state blocks */
3047 if (This->isRecordingState) {
3048 TRACE("Recording... not performing anything\n");
3049 return WINED3D_OK;
3052 /* Compared here and not before the assignment to allow proper stateblock recording */
3053 if(Value == oldValue) {
3054 TRACE("Application is setting the old value over, nothing to do\n");
3055 } else {
3056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3059 return WINED3D_OK;
3062 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3063 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3069 *pValue = This->stateBlock->state.render_states[State];
3070 return WINED3D_OK;
3073 /*****
3074 * Get / Set Sampler States
3075 * TODO: Verify against dx9 definitions
3076 *****/
3078 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 DWORD oldValue;
3082 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3083 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3085 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3086 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3089 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3091 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3092 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3095 oldValue = This->stateBlock->state.sampler_states[Sampler][Type];
3096 This->updateStateBlock->state.sampler_states[Sampler][Type] = Value;
3097 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3099 /* Handle recording of state blocks */
3100 if (This->isRecordingState) {
3101 TRACE("Recording... not performing anything\n");
3102 return WINED3D_OK;
3105 if(oldValue == Value) {
3106 TRACE("Application is setting the old value over, nothing to do\n");
3107 return WINED3D_OK;
3110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3112 return WINED3D_OK;
3115 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3119 This, Sampler, debug_d3dsamplerstate(Type), Type);
3121 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3122 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3125 if (Sampler >= sizeof(This->stateBlock->state.sampler_states) / sizeof(*This->stateBlock->state.sampler_states))
3127 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3128 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3130 *Value = This->stateBlock->state.sampler_states[Sampler][Type];
3131 TRACE("(%p) : Returning %#x\n", This, *Value);
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 This->updateStateBlock->changed.scissorRect = TRUE;
3140 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3142 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3143 return WINED3D_OK;
3145 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3147 if(This->isRecordingState) {
3148 TRACE("Recording... not performing anything\n");
3149 return WINED3D_OK;
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3154 return WINED3D_OK;
3157 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 *pRect = This->updateStateBlock->state.scissor_rect;
3161 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3162 return WINED3D_OK;
3165 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3167 IWineD3DVertexDeclaration *oldDecl = (IWineD3DVertexDeclaration *)This->updateStateBlock->state.vertex_declaration;
3169 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3171 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3172 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3174 This->updateStateBlock->state.vertex_declaration = (IWineD3DVertexDeclarationImpl *)pDecl;
3175 This->updateStateBlock->changed.vertexDecl = TRUE;
3177 if (This->isRecordingState) {
3178 TRACE("Recording... not performing anything\n");
3179 return WINED3D_OK;
3180 } else if(pDecl == oldDecl) {
3181 /* Checked after the assignment to allow proper stateblock recording */
3182 TRACE("Application is setting the old declaration over, nothing to do\n");
3183 return WINED3D_OK;
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3195 *ppDecl = (IWineD3DVertexDeclaration *)This->stateBlock->state.vertex_declaration;
3196 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3197 return WINED3D_OK;
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader *pShader)
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 IWineD3DVertexShader *oldShader = (IWineD3DVertexShader *)This->updateStateBlock->state.vertex_shader;
3205 This->updateStateBlock->state.vertex_shader = (IWineD3DVertexShaderImpl *)pShader;
3206 This->updateStateBlock->changed.vertexShader = TRUE;
3208 if (This->isRecordingState) {
3209 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3210 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3211 TRACE("Recording... not performing anything\n");
3212 return WINED3D_OK;
3213 } else if(oldShader == pShader) {
3214 /* Checked here to allow proper stateblock recording */
3215 TRACE("App is setting the old shader over, nothing to do\n");
3216 return WINED3D_OK;
3219 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3220 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3221 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3225 return WINED3D_OK;
3228 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3230 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3231 IWineD3DVertexShader *shader;
3233 TRACE("iface %p.\n", iface);
3235 shader = (IWineD3DVertexShader *)device->stateBlock->state.vertex_shader;
3236 if (shader) IWineD3DVertexShader_AddRef(shader);
3238 TRACE("Returning %p.\n", shader);
3239 return shader;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3243 IWineD3DDevice *iface,
3244 UINT start,
3245 CONST BOOL *srcData,
3246 UINT count) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3251 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3252 iface, srcData, start, count);
3254 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3256 memcpy(&This->updateStateBlock->state.vs_consts_b[start], srcData, cnt * sizeof(BOOL));
3257 for (i = 0; i < cnt; i++)
3258 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3260 for (i = start; i < cnt + start; ++i) {
3261 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3264 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3266 return WINED3D_OK;
3269 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3270 IWineD3DDevice *iface,
3271 UINT start,
3272 BOOL *dstData,
3273 UINT count) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 int cnt = min(count, MAX_CONST_B - start);
3278 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3279 iface, dstData, start, count);
3281 if (!dstData || cnt < 0)
3282 return WINED3DERR_INVALIDCALL;
3284 memcpy(dstData, &This->stateBlock->state.vs_consts_b[start], cnt * sizeof(BOOL));
3285 return WINED3D_OK;
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3289 IWineD3DDevice *iface,
3290 UINT start,
3291 CONST int *srcData,
3292 UINT count) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3297 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3298 iface, srcData, start, count);
3300 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3302 memcpy(&This->updateStateBlock->state.vs_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3303 for (i = 0; i < cnt; i++)
3304 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3305 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3307 for (i = start; i < cnt + start; ++i) {
3308 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3311 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3313 return WINED3D_OK;
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3317 IWineD3DDevice *iface,
3318 UINT start,
3319 int *dstData,
3320 UINT count) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 int cnt = min(count, MAX_CONST_I - start);
3325 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326 iface, dstData, start, count);
3328 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3329 return WINED3DERR_INVALIDCALL;
3331 memcpy(dstData, &This->stateBlock->state.vs_consts_i[start * 4], cnt * sizeof(int) * 4);
3332 return WINED3D_OK;
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3336 IWineD3DDevice *iface,
3337 UINT start,
3338 CONST float *srcData,
3339 UINT count) {
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342 UINT i;
3344 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3345 iface, srcData, start, count);
3347 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3348 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3349 return WINED3DERR_INVALIDCALL;
3351 memcpy(&This->updateStateBlock->state.vs_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3352 if(TRACE_ON(d3d)) {
3353 for (i = 0; i < count; i++)
3354 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3355 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3358 if (!This->isRecordingState)
3360 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3364 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3365 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3367 return WINED3D_OK;
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3371 IWineD3DDevice *iface,
3372 UINT start,
3373 float *dstData,
3374 UINT count) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 int cnt = min(count, This->d3d_vshader_constantF - start);
3379 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3380 iface, dstData, start, count);
3382 if (!dstData || cnt < 0)
3383 return WINED3DERR_INVALIDCALL;
3385 memcpy(dstData, &This->stateBlock->state.vs_consts_f[start * 4], cnt * sizeof(float) * 4);
3386 return WINED3D_OK;
3389 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3390 DWORD i;
3391 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3397 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3399 DWORD i = This->rev_tex_unit_map[unit];
3400 DWORD j = This->texUnitMap[stage];
3402 This->texUnitMap[stage] = unit;
3403 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3405 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3408 This->rev_tex_unit_map[unit] = stage;
3409 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3411 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3415 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3416 int i;
3418 This->fixed_function_usage_map = 0;
3419 for (i = 0; i < MAX_TEXTURES; ++i)
3421 const struct wined3d_state *state = &This->stateBlock->state;
3422 WINED3DTEXTUREOP color_op = state->texture_states[i][WINED3DTSS_COLOROP];
3423 WINED3DTEXTUREOP alpha_op = state->texture_states[i][WINED3DTSS_ALPHAOP];
3424 DWORD color_arg1 = state->texture_states[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3425 DWORD color_arg2 = state->texture_states[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3426 DWORD color_arg3 = state->texture_states[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3427 DWORD alpha_arg1 = state->texture_states[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3428 DWORD alpha_arg2 = state->texture_states[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3429 DWORD alpha_arg3 = state->texture_states[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3431 if (color_op == WINED3DTOP_DISABLE) {
3432 /* Not used, and disable higher stages */
3433 break;
3436 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3437 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3438 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3439 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3440 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3441 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3442 This->fixed_function_usage_map |= (1 << i);
3445 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3446 This->fixed_function_usage_map |= (1 << (i + 1));
3451 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3453 unsigned int i, tex;
3454 WORD ffu_map;
3456 device_update_fixed_function_usage_map(This);
3457 ffu_map = This->fixed_function_usage_map;
3459 if (This->max_ffp_textures == gl_info->limits.texture_stages
3460 || This->stateBlock->state.lowest_disabled_stage <= This->max_ffp_textures)
3462 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3464 if (!(ffu_map & 1)) continue;
3466 if (This->texUnitMap[i] != i) {
3467 device_map_stage(This, i, i);
3468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3469 markTextureStagesDirty(This, i);
3472 return;
3475 /* Now work out the mapping */
3476 tex = 0;
3477 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3479 if (!(ffu_map & 1)) continue;
3481 if (This->texUnitMap[i] != tex) {
3482 device_map_stage(This, i, tex);
3483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3484 markTextureStagesDirty(This, i);
3487 ++tex;
3491 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3493 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3494 This->stateBlock->state.pixel_shader->baseShader.reg_maps.sampler_type;
3495 unsigned int i;
3497 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3498 if (sampler_type[i] && This->texUnitMap[i] != i)
3500 device_map_stage(This, i, i);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 if (i < gl_info->limits.texture_stages)
3504 markTextureStagesDirty(This, i);
3510 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3511 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3513 DWORD current_mapping = This->rev_tex_unit_map[unit];
3515 /* Not currently used */
3516 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3518 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3519 /* Used by a fragment sampler */
3521 if (!pshader_sampler_tokens) {
3522 /* No pixel shader, check fixed function */
3523 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3526 /* Pixel shader, check the shader's sampler map */
3527 return !pshader_sampler_tokens[current_mapping];
3530 /* Used by a vertex sampler */
3531 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3534 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3536 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3537 This->stateBlock->state.vertex_shader->baseShader.reg_maps.sampler_type;
3538 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3539 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3540 int i;
3542 if (ps)
3544 IWineD3DPixelShaderImpl *pshader = This->stateBlock->state.pixel_shader;
3546 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3547 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3548 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3551 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3552 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3553 if (vshader_sampler_type[i])
3555 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3557 /* Already mapped somewhere */
3558 continue;
3561 while (start >= 0) {
3562 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3564 device_map_stage(This, vsampler_idx, start);
3565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3567 --start;
3568 break;
3571 --start;
3577 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3579 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3580 BOOL vs = use_vs(This->stateBlock);
3581 BOOL ps = use_ps(This->stateBlock);
3583 * Rules are:
3584 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3585 * that would be really messy and require shader recompilation
3586 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3587 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3589 if (ps) device_map_psamplers(This, gl_info);
3590 else device_map_fixed_function_samplers(This, gl_info);
3592 if (vs) device_map_vsamplers(This, ps, gl_info);
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader)
3597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3598 IWineD3DPixelShader *oldShader = (IWineD3DPixelShader *)This->updateStateBlock->state.pixel_shader;
3599 This->updateStateBlock->state.pixel_shader = (IWineD3DPixelShaderImpl *)pShader;
3600 This->updateStateBlock->changed.pixelShader = TRUE;
3602 /* Handle recording of state blocks */
3603 if (This->isRecordingState) {
3604 TRACE("Recording... not performing anything\n");
3607 if (This->isRecordingState) {
3608 TRACE("Recording... not performing anything\n");
3609 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3610 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3611 return WINED3D_OK;
3614 if(pShader == oldShader) {
3615 TRACE("App is setting the old pixel shader over, nothing to do\n");
3616 return WINED3D_OK;
3619 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3620 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3622 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3625 return WINED3D_OK;
3628 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3630 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3631 IWineD3DPixelShader *shader;
3633 TRACE("iface %p.\n", iface);
3635 shader = (IWineD3DPixelShader *)device->stateBlock->state.pixel_shader;
3636 if (shader) IWineD3DPixelShader_AddRef(shader);
3638 TRACE("Returning %p.\n", shader);
3639 return shader;
3642 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3643 IWineD3DDevice *iface,
3644 UINT start,
3645 CONST BOOL *srcData,
3646 UINT count) {
3648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3649 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3651 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3652 iface, srcData, start, count);
3654 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3656 memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
3657 for (i = 0; i < cnt; i++)
3658 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3660 for (i = start; i < cnt + start; ++i) {
3661 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3664 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3666 return WINED3D_OK;
3669 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3670 IWineD3DDevice *iface,
3671 UINT start,
3672 BOOL *dstData,
3673 UINT count) {
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 int cnt = min(count, MAX_CONST_B - start);
3678 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3679 iface, dstData, start, count);
3681 if (!dstData || cnt < 0)
3682 return WINED3DERR_INVALIDCALL;
3684 memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
3685 return WINED3D_OK;
3688 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3689 IWineD3DDevice *iface,
3690 UINT start,
3691 CONST int *srcData,
3692 UINT count) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3697 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3698 iface, srcData, start, count);
3700 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3702 memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
3703 for (i = 0; i < cnt; i++)
3704 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3705 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3707 for (i = start; i < cnt + start; ++i) {
3708 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3711 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3713 return WINED3D_OK;
3716 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3717 IWineD3DDevice *iface,
3718 UINT start,
3719 int *dstData,
3720 UINT count) {
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3723 int cnt = min(count, MAX_CONST_I - start);
3725 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3726 iface, dstData, start, count);
3728 if (!dstData || cnt < 0)
3729 return WINED3DERR_INVALIDCALL;
3731 memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
3732 return WINED3D_OK;
3735 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3736 IWineD3DDevice *iface,
3737 UINT start,
3738 CONST float *srcData,
3739 UINT count) {
3741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3742 UINT i;
3744 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3745 iface, srcData, start, count);
3747 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3748 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3749 return WINED3DERR_INVALIDCALL;
3751 memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
3752 if(TRACE_ON(d3d)) {
3753 for (i = 0; i < count; i++)
3754 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3755 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3758 if (!This->isRecordingState)
3760 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3764 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3765 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3767 return WINED3D_OK;
3770 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3771 IWineD3DDevice *iface,
3772 UINT start,
3773 float *dstData,
3774 UINT count) {
3776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3777 int cnt = min(count, This->d3d_pshader_constantF - start);
3779 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3780 iface, dstData, start, count);
3782 if (!dstData || cnt < 0)
3783 return WINED3DERR_INVALIDCALL;
3785 memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
3786 return WINED3D_OK;
3789 /* Context activation is done by the caller. */
3790 /* Do not call while under the GL lock. */
3791 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3792 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3793 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3794 DWORD DestFVF)
3796 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3797 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3798 unsigned int i;
3799 WINED3DVIEWPORT vp;
3800 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3801 BOOL doClip;
3802 DWORD numTextures;
3804 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3806 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3809 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3811 ERR("Source has no position mask\n");
3812 return WINED3DERR_INVALIDCALL;
3815 if (!dest->resource.allocatedMemory)
3816 buffer_get_sysmem(dest, gl_info);
3818 /* Get a pointer into the destination vbo(create one if none exists) and
3819 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3821 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3823 dest->flags |= WINED3D_BUFFER_CREATEBO;
3824 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3827 if (dest->buffer_object)
3829 unsigned char extrabytes = 0;
3830 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3831 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3832 * this may write 4 extra bytes beyond the area that should be written
3834 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3835 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3836 if(!dest_conv_addr) {
3837 ERR("Out of memory\n");
3838 /* Continue without storing converted vertices */
3840 dest_conv = dest_conv_addr;
3843 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3845 static BOOL warned = FALSE;
3847 * The clipping code is not quite correct. Some things need
3848 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3849 * so disable clipping for now.
3850 * (The graphics in Half-Life are broken, and my processvertices
3851 * test crashes with IDirect3DDevice3)
3852 doClip = TRUE;
3854 doClip = FALSE;
3855 if(!warned) {
3856 warned = TRUE;
3857 FIXME("Clipping is broken and disabled for now\n");
3859 } else doClip = FALSE;
3860 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3862 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3863 WINED3DTS_VIEW,
3864 &view_mat);
3865 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3866 WINED3DTS_PROJECTION,
3867 &proj_mat);
3868 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3869 WINED3DTS_WORLDMATRIX(0),
3870 &world_mat);
3872 TRACE("View mat:\n");
3873 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);
3874 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);
3875 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);
3876 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);
3878 TRACE("Proj mat:\n");
3879 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);
3880 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);
3881 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);
3882 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);
3884 TRACE("World mat:\n");
3885 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);
3886 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);
3887 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);
3888 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);
3890 /* Get the viewport */
3891 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3892 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3893 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3895 multiply_matrix(&mat,&view_mat,&world_mat);
3896 multiply_matrix(&mat,&proj_mat,&mat);
3898 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3900 for (i = 0; i < dwCount; i+= 1) {
3901 unsigned int tex_index;
3903 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3904 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3905 /* The position first */
3906 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3907 const float *p = (const float *)(element->data + i * element->stride);
3908 float x, y, z, rhw;
3909 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3911 /* Multiplication with world, view and projection matrix */
3912 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);
3913 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);
3914 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);
3915 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);
3917 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3919 /* WARNING: The following things are taken from d3d7 and were not yet checked
3920 * against d3d8 or d3d9!
3923 /* Clipping conditions: From msdn
3925 * A vertex is clipped if it does not match the following requirements
3926 * -rhw < x <= rhw
3927 * -rhw < y <= rhw
3928 * 0 < z <= rhw
3929 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3931 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3932 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3936 if( !doClip ||
3937 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3938 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3939 ( rhw > eps ) ) ) {
3941 /* "Normal" viewport transformation (not clipped)
3942 * 1) The values are divided by rhw
3943 * 2) The y axis is negative, so multiply it with -1
3944 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3945 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3946 * 4) Multiply x with Width/2 and add Width/2
3947 * 5) The same for the height
3948 * 6) Add the viewpoint X and Y to the 2D coordinates and
3949 * The minimum Z value to z
3950 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3952 * Well, basically it's simply a linear transformation into viewport
3953 * coordinates
3956 x /= rhw;
3957 y /= rhw;
3958 z /= rhw;
3960 y *= -1;
3962 x *= vp.Width / 2;
3963 y *= vp.Height / 2;
3964 z *= vp.MaxZ - vp.MinZ;
3966 x += vp.Width / 2 + vp.X;
3967 y += vp.Height / 2 + vp.Y;
3968 z += vp.MinZ;
3970 rhw = 1 / rhw;
3971 } else {
3972 /* That vertex got clipped
3973 * Contrary to OpenGL it is not dropped completely, it just
3974 * undergoes a different calculation.
3976 TRACE("Vertex got clipped\n");
3977 x += rhw;
3978 y += rhw;
3980 x /= 2;
3981 y /= 2;
3983 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3984 * outside of the main vertex buffer memory. That needs some more
3985 * investigation...
3989 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3992 ( (float *) dest_ptr)[0] = x;
3993 ( (float *) dest_ptr)[1] = y;
3994 ( (float *) dest_ptr)[2] = z;
3995 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3997 dest_ptr += 3 * sizeof(float);
3999 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4000 dest_ptr += sizeof(float);
4003 if(dest_conv) {
4004 float w = 1 / rhw;
4005 ( (float *) dest_conv)[0] = x * w;
4006 ( (float *) dest_conv)[1] = y * w;
4007 ( (float *) dest_conv)[2] = z * w;
4008 ( (float *) dest_conv)[3] = w;
4010 dest_conv += 3 * sizeof(float);
4012 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4013 dest_conv += sizeof(float);
4017 if (DestFVF & WINED3DFVF_PSIZE) {
4018 dest_ptr += sizeof(DWORD);
4019 if(dest_conv) dest_conv += sizeof(DWORD);
4021 if (DestFVF & WINED3DFVF_NORMAL) {
4022 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4023 const float *normal = (const float *)(element->data + i * element->stride);
4024 /* AFAIK this should go into the lighting information */
4025 FIXME("Didn't expect the destination to have a normal\n");
4026 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4027 if(dest_conv) {
4028 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4032 if (DestFVF & WINED3DFVF_DIFFUSE) {
4033 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4034 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4035 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4037 static BOOL warned = FALSE;
4039 if(!warned) {
4040 ERR("No diffuse color in source, but destination has one\n");
4041 warned = TRUE;
4044 *( (DWORD *) dest_ptr) = 0xffffffff;
4045 dest_ptr += sizeof(DWORD);
4047 if(dest_conv) {
4048 *( (DWORD *) dest_conv) = 0xffffffff;
4049 dest_conv += sizeof(DWORD);
4052 else {
4053 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4054 if(dest_conv) {
4055 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4056 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4057 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4058 dest_conv += sizeof(DWORD);
4063 if (DestFVF & WINED3DFVF_SPECULAR)
4065 /* What's the color value in the feedback buffer? */
4066 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4067 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4068 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4070 static BOOL warned = FALSE;
4072 if(!warned) {
4073 ERR("No specular color in source, but destination has one\n");
4074 warned = TRUE;
4077 *( (DWORD *) dest_ptr) = 0xFF000000;
4078 dest_ptr += sizeof(DWORD);
4080 if(dest_conv) {
4081 *( (DWORD *) dest_conv) = 0xFF000000;
4082 dest_conv += sizeof(DWORD);
4085 else {
4086 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4087 if(dest_conv) {
4088 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4089 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4090 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4091 dest_conv += sizeof(DWORD);
4096 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4097 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4098 const float *tex_coord = (const float *)(element->data + i * element->stride);
4099 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4101 ERR("No source texture, but destination requests one\n");
4102 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4103 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4105 else {
4106 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4107 if(dest_conv) {
4108 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4114 if (dest_conv)
4116 ENTER_GL();
4118 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4119 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4120 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4121 dwCount * get_flexible_vertex_size(DestFVF),
4122 dest_conv_addr));
4123 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4125 LEAVE_GL();
4127 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4130 return WINED3D_OK;
4132 #undef copy_and_next
4134 /* Do not call while under the GL lock. */
4135 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4136 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4137 DWORD DestFVF)
4139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4140 struct wined3d_stream_info stream_info;
4141 const struct wined3d_gl_info *gl_info;
4142 struct wined3d_context *context;
4143 BOOL vbo = FALSE, streamWasUP = This->stateBlock->state.user_stream;
4144 HRESULT hr;
4146 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4148 if(pVertexDecl) {
4149 ERR("Output vertex declaration not implemented yet\n");
4152 /* Need any context to write to the vbo. */
4153 context = context_acquire(This, NULL);
4154 gl_info = context->gl_info;
4156 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4157 * control the streamIsUP flag, thus restore it afterwards.
4159 This->stateBlock->state.user_stream = FALSE;
4160 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4161 This->stateBlock->state.user_stream = streamWasUP;
4163 if(vbo || SrcStartIndex) {
4164 unsigned int i;
4165 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4166 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4168 * Also get the start index in, but only loop over all elements if there's something to add at all.
4170 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4172 struct wined3d_stream_info_element *e;
4174 if (!(stream_info.use_map & (1 << i))) continue;
4176 e = &stream_info.elements[i];
4177 if (e->buffer_object)
4179 struct wined3d_buffer *vb = This->stateBlock->state.streams[e->stream_idx].buffer;
4180 e->buffer_object = 0;
4181 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4182 ENTER_GL();
4183 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4184 vb->buffer_object = 0;
4185 LEAVE_GL();
4187 if (e->data) e->data += e->stride * SrcStartIndex;
4191 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4192 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4194 context_release(context);
4196 return hr;
4199 /*****
4200 * Get / Set Texture Stage States
4201 * TODO: Verify against dx9 definitions
4202 *****/
4203 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4206 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4207 DWORD oldValue;
4209 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4211 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4213 WARN("Invalid Type %d passed.\n", Type);
4214 return WINED3D_OK;
4217 if (Stage >= gl_info->limits.texture_stages)
4219 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4220 Stage, gl_info->limits.texture_stages - 1);
4221 return WINED3D_OK;
4224 oldValue = This->updateStateBlock->state.texture_states[Stage][Type];
4225 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4226 This->updateStateBlock->state.texture_states[Stage][Type] = Value;
4228 if (This->isRecordingState) {
4229 TRACE("Recording... not performing anything\n");
4230 return WINED3D_OK;
4233 /* Checked after the assignments to allow proper stateblock recording */
4234 if(oldValue == Value) {
4235 TRACE("App is setting the old value over, nothing to do\n");
4236 return WINED3D_OK;
4239 if (Stage > This->stateBlock->state.lowest_disabled_stage
4240 && This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative
4241 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP))
4243 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4244 * Changes in other states are important on disabled stages too
4246 return WINED3D_OK;
4249 if(Type == WINED3DTSS_COLOROP) {
4250 unsigned int i;
4252 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4253 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4254 * they have to be disabled
4256 * The current stage is dirtified below.
4258 for (i = Stage + 1; i < This->stateBlock->state.lowest_disabled_stage; ++i)
4260 TRACE("Additionally dirtifying stage %u\n", i);
4261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4263 This->stateBlock->state.lowest_disabled_stage = Stage;
4264 TRACE("New lowest disabled: %u\n", Stage);
4265 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4266 /* Previously disabled stage enabled. Stages above it may need enabling
4267 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4268 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4270 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4273 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4275 if (This->updateStateBlock->state.texture_states[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE)
4276 break;
4277 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4280 This->stateBlock->state.lowest_disabled_stage = i;
4281 TRACE("New lowest disabled: %u\n", i);
4285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4287 return WINED3D_OK;
4290 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4294 TRACE("iface %p, stage %u, state %s, value %p.\n",
4295 iface, Stage, debug_d3dtexturestate(Type), pValue);
4297 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4299 WARN("Invalid Type %d passed.\n", Type);
4300 return WINED3D_OK;
4303 *pValue = This->updateStateBlock->state.texture_states[Stage][Type];
4304 TRACE("Returning %#x.\n", *pValue);
4306 return WINED3D_OK;
4309 /*****
4310 * Get / Set Texture
4311 *****/
4312 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4313 DWORD stage, IWineD3DBaseTexture *texture)
4315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4316 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4317 IWineD3DBaseTexture *prev;
4319 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4321 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4322 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4324 /* Windows accepts overflowing this array... we do not. */
4325 if (stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4327 WARN("Ignoring invalid stage %u.\n", stage);
4328 return WINED3D_OK;
4331 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4332 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4334 WARN("Rejecting attempt to set scratch texture.\n");
4335 return WINED3DERR_INVALIDCALL;
4338 This->updateStateBlock->changed.textures |= 1 << stage;
4340 prev = (IWineD3DBaseTexture *)This->updateStateBlock->state.textures[stage];
4341 TRACE("Previous texture %p.\n", prev);
4343 if (texture == prev)
4345 TRACE("App is setting the same texture again, nothing to do.\n");
4346 return WINED3D_OK;
4349 TRACE("Setting new texture to %p.\n", texture);
4350 This->updateStateBlock->state.textures[stage] = (IWineD3DBaseTextureImpl *)texture;
4352 if (This->isRecordingState)
4354 TRACE("Recording... not performing anything\n");
4356 if (texture) IWineD3DBaseTexture_AddRef(texture);
4357 if (prev) IWineD3DBaseTexture_Release(prev);
4359 return WINED3D_OK;
4362 if (texture)
4364 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4365 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4366 GLenum dimensions = t->baseTexture.target;
4368 IWineD3DBaseTexture_AddRef(texture);
4370 if (!prev || dimensions != ((IWineD3DBaseTextureImpl *)prev)->baseTexture.target)
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4373 if (!prev && stage < gl_info->limits.texture_stages)
4375 /* The source arguments for color and alpha ops have different
4376 * meanings when a NULL texture is bound, so the COLOROP and
4377 * ALPHAOP have to be dirtified. */
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4382 if (bind_count == 1) t->baseTexture.sampler = stage;
4385 if (prev)
4387 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4388 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4390 IWineD3DBaseTexture_Release(prev);
4392 if (!texture && stage < gl_info->limits.texture_stages)
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4398 if (bind_count && t->baseTexture.sampler == stage)
4400 unsigned int i;
4402 /* Search for other stages the texture is bound to. Shouldn't
4403 * happen if applications bind textures to a single stage only. */
4404 TRACE("Searching for other stages the texture is bound to.\n");
4405 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4407 if (This->updateStateBlock->state.textures[i] == t)
4409 TRACE("Texture is also bound to stage %u.\n", i);
4410 t->baseTexture.sampler = i;
4411 break;
4417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4419 return WINED3D_OK;
4422 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4427 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4428 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4431 if (Stage >= sizeof(This->stateBlock->state.textures) / sizeof(*This->stateBlock->state.textures))
4433 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4434 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4437 *ppTexture = (IWineD3DBaseTexture *)This->stateBlock->state.textures[Stage];
4438 if (*ppTexture)
4439 IWineD3DBaseTexture_AddRef(*ppTexture);
4441 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4443 return WINED3D_OK;
4446 /*****
4447 * Get Back Buffer
4448 *****/
4449 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4450 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4452 IWineD3DSwapChain *swapchain;
4453 HRESULT hr;
4455 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4456 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4458 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4459 if (FAILED(hr))
4461 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4462 return hr;
4465 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4466 IWineD3DSwapChain_Release(swapchain);
4467 if (FAILED(hr))
4469 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4470 return hr;
4473 return WINED3D_OK;
4476 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 WARN("(%p) : stub, calling idirect3d for now\n", This);
4479 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4482 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 IWineD3DSwapChain *swapChain;
4485 HRESULT hr;
4487 if(iSwapChain > 0) {
4488 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4489 if (hr == WINED3D_OK) {
4490 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4491 IWineD3DSwapChain_Release(swapChain);
4492 } else {
4493 FIXME("(%p) Error getting display mode\n", This);
4495 } else {
4496 /* Don't read the real display mode,
4497 but return the stored mode instead. X11 can't change the color
4498 depth, and some apps are pretty angry if they SetDisplayMode from
4499 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4501 Also don't relay to the swapchain because with ddraw it's possible
4502 that there isn't a swapchain at all */
4503 pMode->Width = This->ddraw_width;
4504 pMode->Height = This->ddraw_height;
4505 pMode->Format = This->ddraw_format;
4506 pMode->RefreshRate = 0;
4507 hr = WINED3D_OK;
4510 return hr;
4513 /*****
4514 * Stateblock related functions
4515 *****/
4517 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 IWineD3DStateBlock *stateblock;
4520 HRESULT hr;
4522 TRACE("(%p)\n", This);
4524 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4526 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4527 if (FAILED(hr)) return hr;
4529 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4530 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4531 This->isRecordingState = TRUE;
4533 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4535 return WINED3D_OK;
4538 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4542 if (!This->isRecordingState) {
4543 WARN("(%p) not recording! returning error\n", This);
4544 *ppStateBlock = NULL;
4545 return WINED3DERR_INVALIDCALL;
4548 stateblock_init_contained_states(object);
4550 *ppStateBlock = (IWineD3DStateBlock*) object;
4551 This->isRecordingState = FALSE;
4552 This->updateStateBlock = This->stateBlock;
4553 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4554 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4555 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4556 return WINED3D_OK;
4559 /*****
4560 * Scene related functions
4561 *****/
4562 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4563 /* At the moment we have no need for any functionality at the beginning
4564 of a scene */
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p)\n", This);
4568 if(This->inScene) {
4569 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4570 return WINED3DERR_INVALIDCALL;
4572 This->inScene = TRUE;
4573 return WINED3D_OK;
4576 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 struct wined3d_context *context;
4581 TRACE("(%p)\n", This);
4583 if(!This->inScene) {
4584 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4585 return WINED3DERR_INVALIDCALL;
4588 context = context_acquire(This, NULL);
4589 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4590 wglFlush();
4591 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4592 * fails. */
4593 context_release(context);
4595 This->inScene = FALSE;
4596 return WINED3D_OK;
4599 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4600 const RECT *pSourceRect, const RECT *pDestRect,
4601 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4603 IWineD3DSwapChain *swapChain = NULL;
4604 int i;
4605 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4607 TRACE("iface %p.\n", iface);
4609 for(i = 0 ; i < swapchains ; i ++) {
4611 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4612 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4613 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4614 IWineD3DSwapChain_Release(swapChain);
4617 return WINED3D_OK;
4620 /* Do not call while under the GL lock. */
4621 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4622 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4624 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4625 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4626 RECT draw_rect;
4628 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4629 iface, rect_count, rects, flags, color, depth, stencil);
4631 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4633 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4634 /* TODO: What about depth stencil buffers without stencil bits? */
4635 return WINED3DERR_INVALIDCALL;
4638 device_get_draw_rect(device, &draw_rect);
4640 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4641 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4644 /*****
4645 * Drawing functions
4646 *****/
4648 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4649 WINED3DPRIMITIVETYPE primitive_type)
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4653 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4655 This->updateStateBlock->changed.primitive_type = TRUE;
4656 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4659 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4660 WINED3DPRIMITIVETYPE *primitive_type)
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4666 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4668 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4671 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4677 if (!This->stateBlock->state.vertex_declaration)
4679 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4680 return WINED3DERR_INVALIDCALL;
4683 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4684 if (This->stateBlock->state.user_stream)
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4687 This->stateBlock->state.user_stream = FALSE;
4690 if (This->stateBlock->loadBaseVertexIndex)
4692 This->stateBlock->loadBaseVertexIndex = 0;
4693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4695 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4696 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4697 return WINED3D_OK;
4700 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 struct wined3d_buffer *index_buffer;
4704 UINT idxStride = 2;
4705 GLuint vbo;
4707 index_buffer = This->stateBlock->state.index_buffer;
4708 if (!index_buffer)
4710 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4711 * without an index buffer set. (The first time at least...)
4712 * D3D8 simply dies, but I doubt it can do much harm to return
4713 * D3DERR_INVALIDCALL there as well. */
4714 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4715 return WINED3DERR_INVALIDCALL;
4718 if (!This->stateBlock->state.vertex_declaration)
4720 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4721 return WINED3DERR_INVALIDCALL;
4724 if (This->stateBlock->state.user_stream)
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4727 This->stateBlock->state.user_stream = FALSE;
4729 vbo = index_buffer->buffer_object;
4731 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4733 if (This->stateBlock->state.index_format == WINED3DFMT_R16_UINT)
4734 idxStride = 2;
4735 else
4736 idxStride = 4;
4738 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4739 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4743 drawPrimitive(iface, index_count, startIndex, idxStride,
4744 vbo ? NULL : index_buffer->resource.allocatedMemory);
4746 return WINED3D_OK;
4749 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4750 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 struct wined3d_stream_state *stream;
4754 IWineD3DBuffer *vb;
4756 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4757 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4759 if (!This->stateBlock->state.vertex_declaration)
4761 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4762 return WINED3DERR_INVALIDCALL;
4765 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4766 stream = &This->stateBlock->state.streams[0];
4767 vb = (IWineD3DBuffer *)stream->buffer;
4768 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4769 if (vb) IWineD3DBuffer_Release(vb);
4770 stream->offset = 0;
4771 stream->stride = VertexStreamZeroStride;
4772 This->stateBlock->state.user_stream = TRUE;
4773 This->stateBlock->loadBaseVertexIndex = 0;
4775 /* TODO: Only mark dirty if drawing from a different UP address */
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4778 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4780 /* MSDN specifies stream zero settings must be set to NULL */
4781 stream->buffer = NULL;
4782 stream->stride = 0;
4784 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4785 * the new stream sources or use UP drawing again
4787 return WINED3D_OK;
4790 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4791 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4792 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4794 int idxStride;
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 struct wined3d_stream_state *stream;
4797 IWineD3DBuffer *vb;
4798 IWineD3DBuffer *ib;
4800 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4801 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4803 if (!This->stateBlock->state.vertex_declaration)
4805 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4806 return WINED3DERR_INVALIDCALL;
4809 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4810 idxStride = 2;
4811 } else {
4812 idxStride = 4;
4815 stream = &This->stateBlock->state.streams[0];
4816 vb = (IWineD3DBuffer *)stream->buffer;
4817 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4818 if (vb) IWineD3DBuffer_Release(vb);
4819 stream->offset = 0;
4820 stream->stride = VertexStreamZeroStride;
4821 This->stateBlock->state.user_stream = TRUE;
4823 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4824 This->stateBlock->baseVertexIndex = 0;
4825 This->stateBlock->loadBaseVertexIndex = 0;
4826 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4830 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4832 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4833 stream->buffer = NULL;
4834 stream->stride = 0;
4835 ib = (IWineD3DBuffer *)This->stateBlock->state.index_buffer;
4836 if (ib)
4838 IWineD3DBuffer_Release(ib);
4839 This->stateBlock->state.index_buffer = NULL;
4841 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4842 * SetStreamSource to specify a vertex buffer
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4849 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4853 /* Mark the state dirty until we have nicer tracking
4854 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4855 * that value.
4857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4859 This->stateBlock->baseVertexIndex = 0;
4860 This->up_strided = DrawPrimStrideData;
4861 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4862 This->up_strided = NULL;
4863 return WINED3D_OK;
4866 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4867 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4868 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4871 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4873 /* Mark the state dirty until we have nicer tracking
4874 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4875 * that value.
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4879 This->stateBlock->state.user_stream = TRUE;
4880 This->stateBlock->baseVertexIndex = 0;
4881 This->up_strided = DrawPrimStrideData;
4882 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4883 This->up_strided = NULL;
4884 return WINED3D_OK;
4887 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4888 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4889 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4891 WINED3DLOCKED_BOX src;
4892 WINED3DLOCKED_BOX dst;
4893 HRESULT hr;
4895 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4896 iface, pSourceVolume, pDestinationVolume);
4898 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4899 * dirtification to improve loading performance.
4901 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4902 if(FAILED(hr)) return hr;
4903 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4904 if(FAILED(hr)) {
4905 IWineD3DVolume_UnlockBox(pSourceVolume);
4906 return hr;
4909 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4911 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4912 if(FAILED(hr)) {
4913 IWineD3DVolume_UnlockBox(pSourceVolume);
4914 } else {
4915 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4917 return hr;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4921 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4923 unsigned int level_count, i;
4924 WINED3DRESOURCETYPE type;
4925 HRESULT hr;
4927 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4929 /* Verify that the source and destination textures are non-NULL. */
4930 if (!src_texture || !dst_texture)
4932 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4933 return WINED3DERR_INVALIDCALL;
4936 if (src_texture == dst_texture)
4938 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4939 return WINED3DERR_INVALIDCALL;
4942 /* Verify that the source and destination textures are the same type. */
4943 type = IWineD3DBaseTexture_GetType(src_texture);
4944 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4946 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4947 return WINED3DERR_INVALIDCALL;
4950 /* Check that both textures have the identical numbers of levels. */
4951 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4952 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4954 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4955 return WINED3DERR_INVALIDCALL;
4958 /* Make sure that the destination texture is loaded. */
4959 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4961 /* Update every surface level of the texture. */
4962 switch (type)
4964 case WINED3DRTYPE_TEXTURE:
4966 IWineD3DSurface *src_surface;
4967 IWineD3DSurface *dst_surface;
4969 for (i = 0; i < level_count; ++i)
4971 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4972 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4973 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4974 IWineD3DSurface_Release(dst_surface);
4975 IWineD3DSurface_Release(src_surface);
4976 if (FAILED(hr))
4978 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4979 return hr;
4982 break;
4985 case WINED3DRTYPE_CUBETEXTURE:
4987 IWineD3DSurface *src_surface;
4988 IWineD3DSurface *dst_surface;
4989 WINED3DCUBEMAP_FACES face;
4991 for (i = 0; i < level_count; ++i)
4993 /* Update each cube face. */
4994 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4996 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4997 face, i, &src_surface);
4998 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4999 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5000 face, i, &dst_surface);
5001 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5002 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5003 IWineD3DSurface_Release(dst_surface);
5004 IWineD3DSurface_Release(src_surface);
5005 if (FAILED(hr))
5007 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5008 return hr;
5012 break;
5015 case WINED3DRTYPE_VOLUMETEXTURE:
5017 IWineD3DVolume *src_volume;
5018 IWineD3DVolume *dst_volume;
5020 for (i = 0; i < level_count; ++i)
5022 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5023 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5024 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5025 IWineD3DVolume_Release(dst_volume);
5026 IWineD3DVolume_Release(src_volume);
5027 if (FAILED(hr))
5029 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5030 return hr;
5033 break;
5036 default:
5037 FIXME("Unsupported texture type %#x.\n", type);
5038 return WINED3DERR_INVALIDCALL;
5041 return WINED3D_OK;
5044 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5045 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5047 IWineD3DSwapChain *swapchain;
5048 HRESULT hr;
5050 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5052 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5053 if (FAILED(hr)) return hr;
5055 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5056 IWineD3DSwapChain_Release(swapchain);
5058 return hr;
5061 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 IWineD3DBaseTextureImpl *texture;
5064 DWORD i;
5066 TRACE("(%p) : %p\n", This, pNumPasses);
5068 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5070 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE)
5072 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5073 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5075 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE)
5077 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5078 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5081 texture = This->stateBlock->state.textures[i];
5082 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5084 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT)
5086 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5087 return E_FAIL;
5089 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT)
5091 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5092 return E_FAIL;
5094 if (This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE
5095 && This->stateBlock->state.sampler_states[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT)
5097 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5098 return E_FAIL;
5102 /* return a sensible default */
5103 *pNumPasses = 1;
5105 TRACE("returning D3D_OK\n");
5106 return WINED3D_OK;
5109 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5111 int i;
5113 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5115 IWineD3DBaseTextureImpl *texture = device->stateBlock->state.textures[i];
5116 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5117 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5119 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5124 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 int j;
5127 UINT NewSize;
5128 PALETTEENTRY **palettes;
5130 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5132 if (PaletteNumber >= MAX_PALETTES) {
5133 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5134 return WINED3DERR_INVALIDCALL;
5137 if (PaletteNumber >= This->NumberOfPalettes) {
5138 NewSize = This->NumberOfPalettes;
5139 do {
5140 NewSize *= 2;
5141 } while(PaletteNumber >= NewSize);
5142 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5143 if (!palettes) {
5144 ERR("Out of memory!\n");
5145 return E_OUTOFMEMORY;
5147 This->palettes = palettes;
5148 This->NumberOfPalettes = NewSize;
5151 if (!This->palettes[PaletteNumber]) {
5152 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5153 if (!This->palettes[PaletteNumber]) {
5154 ERR("Out of memory!\n");
5155 return E_OUTOFMEMORY;
5159 for (j = 0; j < 256; ++j) {
5160 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5161 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5162 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5163 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5165 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5166 TRACE("(%p) : returning\n", This);
5167 return WINED3D_OK;
5170 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5172 int j;
5173 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5174 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5175 /* What happens in such situation isn't documented; Native seems to silently abort
5176 on such conditions. Return Invalid Call. */
5177 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5178 return WINED3DERR_INVALIDCALL;
5180 for (j = 0; j < 256; ++j) {
5181 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5182 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5183 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5184 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5186 TRACE("(%p) : returning\n", This);
5187 return WINED3D_OK;
5190 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5192 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5193 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5194 (tested with reference rasterizer). Return Invalid Call. */
5195 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5196 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5197 return WINED3DERR_INVALIDCALL;
5199 /*TODO: stateblocks */
5200 if (This->currentPalette != PaletteNumber) {
5201 This->currentPalette = PaletteNumber;
5202 dirtify_p8_texture_samplers(This);
5204 TRACE("(%p) : returning\n", This);
5205 return WINED3D_OK;
5208 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 if (!PaletteNumber)
5213 WARN("(%p) : returning Invalid Call\n", This);
5214 return WINED3DERR_INVALIDCALL;
5216 /*TODO: stateblocks */
5217 *PaletteNumber = This->currentPalette;
5218 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5219 return WINED3D_OK;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5224 static BOOL warned;
5225 if (!warned)
5227 FIXME("(%p) : stub\n", This);
5228 warned = TRUE;
5231 This->softwareVertexProcessing = bSoftware;
5232 return WINED3D_OK;
5236 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 static BOOL warned;
5239 if (!warned)
5241 FIXME("(%p) : stub\n", This);
5242 warned = TRUE;
5244 return This->softwareVertexProcessing;
5247 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5248 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5250 IWineD3DSwapChain *swapchain;
5251 HRESULT hr;
5253 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5254 iface, swapchain_idx, raster_status);
5256 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5257 if (FAILED(hr))
5259 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5260 return hr;
5263 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5264 IWineD3DSwapChain_Release(swapchain);
5265 if (FAILED(hr))
5267 WARN("Failed to get raster status, hr %#x.\n", hr);
5268 return hr;
5271 return WINED3D_OK;
5274 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5276 static BOOL warned;
5277 if(nSegments != 0.0f) {
5278 if (!warned)
5280 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5281 warned = TRUE;
5284 return WINED3D_OK;
5287 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5289 static BOOL warned;
5290 if (!warned)
5292 FIXME("iface %p stub!\n", iface);
5293 warned = TRUE;
5295 return 0.0f;
5298 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5299 IWineD3DSurface *src_surface, const RECT *src_rect,
5300 IWineD3DSurface *dst_surface, const POINT *dst_point)
5302 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5303 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5305 const struct wined3d_format *src_format;
5306 const struct wined3d_format *dst_format;
5307 const struct wined3d_gl_info *gl_info;
5308 struct wined3d_context *context;
5309 const unsigned char *data;
5310 UINT update_w, update_h;
5311 CONVERT_TYPES convert;
5312 UINT src_w, src_h;
5313 UINT dst_x, dst_y;
5314 DWORD sampler;
5315 struct wined3d_format format;
5317 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5318 iface, src_surface, wine_dbgstr_rect(src_rect),
5319 dst_surface, wine_dbgstr_point(dst_point));
5321 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5323 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5324 src_surface, dst_surface);
5325 return WINED3DERR_INVALIDCALL;
5328 src_format = src_impl->resource.format;
5329 dst_format = dst_impl->resource.format;
5331 if (src_format->id != dst_format->id)
5333 WARN("Source and destination surfaces should have the same format.\n");
5334 return WINED3DERR_INVALIDCALL;
5337 dst_x = dst_point ? dst_point->x : 0;
5338 dst_y = dst_point ? dst_point->y : 0;
5340 /* This call loads the OpenGL surface directly, instead of copying the
5341 * surface to the destination's sysmem copy. If surface conversion is
5342 * needed, use BltFast instead to copy in sysmem and use regular surface
5343 * loading. */
5344 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5345 if (convert != NO_CONVERSION || format.convert)
5346 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5348 context = context_acquire(This, NULL);
5349 gl_info = context->gl_info;
5351 ENTER_GL();
5352 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5353 checkGLcall("glActiveTextureARB");
5354 LEAVE_GL();
5356 /* Make sure the surface is loaded and up to date */
5357 surface_internal_preload(dst_impl, SRGB_RGB);
5358 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5360 src_w = src_impl->currentDesc.Width;
5361 src_h = src_impl->currentDesc.Height;
5362 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5363 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5365 data = IWineD3DSurface_GetData(src_surface);
5366 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5368 ENTER_GL();
5370 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5372 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5373 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5374 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5376 if (src_rect)
5378 data += (src_rect->top / src_format->block_height) * src_pitch;
5379 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5382 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5383 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5384 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5386 if (row_length == src_pitch)
5388 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5389 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5391 else
5393 UINT row, y;
5395 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5396 * can't use the unpack row length like below. */
5397 for (row = 0, y = dst_y; row < row_count; ++row)
5399 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5400 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5401 y += src_format->block_height;
5402 data += src_pitch;
5405 checkGLcall("glCompressedTexSubImage2DARB");
5407 else
5409 if (src_rect)
5411 data += src_rect->top * src_w * src_format->byte_count;
5412 data += src_rect->left * src_format->byte_count;
5415 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5416 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5417 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5419 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5420 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5421 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5422 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5423 checkGLcall("glTexSubImage2D");
5426 LEAVE_GL();
5427 context_release(context);
5429 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5430 sampler = This->rev_tex_unit_map[0];
5431 if (sampler != WINED3D_UNMAPPED_STAGE)
5433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5436 return WINED3D_OK;
5439 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 struct WineD3DRectPatch *patch;
5442 GLenum old_primitive_type;
5443 unsigned int i;
5444 struct list *e;
5445 BOOL found;
5446 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5448 if(!(Handle || pRectPatchInfo)) {
5449 /* TODO: Write a test for the return value, thus the FIXME */
5450 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5451 return WINED3DERR_INVALIDCALL;
5454 if(Handle) {
5455 i = PATCHMAP_HASHFUNC(Handle);
5456 found = FALSE;
5457 LIST_FOR_EACH(e, &This->patches[i]) {
5458 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5459 if(patch->Handle == Handle) {
5460 found = TRUE;
5461 break;
5465 if(!found) {
5466 TRACE("Patch does not exist. Creating a new one\n");
5467 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5468 patch->Handle = Handle;
5469 list_add_head(&This->patches[i], &patch->entry);
5470 } else {
5471 TRACE("Found existing patch %p\n", patch);
5473 } else {
5474 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5475 * attributes we have to tesselate, read back, and draw. This needs a patch
5476 * management structure instance. Create one.
5478 * A possible improvement is to check if a vertex shader is used, and if not directly
5479 * draw the patch.
5481 FIXME("Drawing an uncached patch. This is slow\n");
5482 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5485 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5486 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5487 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5489 HRESULT hr;
5490 TRACE("Tesselation density or patch info changed, retesselating\n");
5492 if(pRectPatchInfo) {
5493 patch->RectPatchInfo = *pRectPatchInfo;
5495 patch->numSegs[0] = pNumSegs[0];
5496 patch->numSegs[1] = pNumSegs[1];
5497 patch->numSegs[2] = pNumSegs[2];
5498 patch->numSegs[3] = pNumSegs[3];
5500 hr = tesselate_rectpatch(This, patch);
5501 if(FAILED(hr)) {
5502 WARN("Patch tesselation failed\n");
5504 /* Do not release the handle to store the params of the patch */
5505 if(!Handle) {
5506 HeapFree(GetProcessHeap(), 0, patch);
5508 return hr;
5512 This->currentPatch = patch;
5513 old_primitive_type = This->stateBlock->gl_primitive_type;
5514 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5515 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5516 This->stateBlock->gl_primitive_type = old_primitive_type;
5517 This->currentPatch = NULL;
5519 /* Destroy uncached patches */
5520 if(!Handle) {
5521 HeapFree(GetProcessHeap(), 0, patch->mem);
5522 HeapFree(GetProcessHeap(), 0, patch);
5524 return WINED3D_OK;
5527 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5528 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5530 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5531 iface, handle, segment_count, patch_info);
5533 return WINED3D_OK;
5536 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 int i;
5539 struct WineD3DRectPatch *patch;
5540 struct list *e;
5541 TRACE("(%p) Handle(%d)\n", This, Handle);
5543 i = PATCHMAP_HASHFUNC(Handle);
5544 LIST_FOR_EACH(e, &This->patches[i]) {
5545 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5546 if(patch->Handle == Handle) {
5547 TRACE("Deleting patch %p\n", patch);
5548 list_remove(&patch->entry);
5549 HeapFree(GetProcessHeap(), 0, patch->mem);
5550 HeapFree(GetProcessHeap(), 0, patch);
5551 return WINED3D_OK;
5555 /* TODO: Write a test for the return value */
5556 FIXME("Attempt to destroy nonexistent patch\n");
5557 return WINED3DERR_INVALIDCALL;
5560 /* Do not call while under the GL lock. */
5561 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5562 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5564 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5566 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5567 iface, surface, wine_dbgstr_rect(rect),
5568 color->r, color->g, color->b, color->a);
5570 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5572 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5573 return WINED3DERR_INVALIDCALL;
5576 return surface_color_fill(s, rect, color);
5579 /* Do not call while under the GL lock. */
5580 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5581 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5583 IWineD3DResource *resource;
5584 HRESULT hr;
5586 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5587 if (FAILED(hr))
5589 ERR("Failed to get resource, hr %#x\n", hr);
5590 return;
5593 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5595 FIXME("Only supported on surface resources\n");
5596 IWineD3DResource_Release(resource);
5597 return;
5600 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5601 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5603 IWineD3DResource_Release(resource);
5606 /* rendertarget and depth stencil functions */
5607 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5608 DWORD render_target_idx, IWineD3DSurface **render_target)
5610 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5612 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5613 iface, render_target_idx, render_target);
5615 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5617 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5618 return WINED3DERR_INVALIDCALL;
5621 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5622 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5624 TRACE("Returning render target %p.\n", *render_target);
5626 return WINED3D_OK;
5629 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5630 IWineD3DSurface *front, IWineD3DSurface *back)
5632 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5633 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5634 IWineD3DSwapChainImpl *swapchain;
5635 HRESULT hr;
5637 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5639 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5641 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5642 return hr;
5645 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5647 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5648 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5649 return WINED3DERR_INVALIDCALL;
5652 if (back_impl)
5654 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5656 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5657 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5658 return WINED3DERR_INVALIDCALL;
5661 if (!swapchain->back_buffers)
5663 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5664 if (!swapchain->back_buffers)
5666 ERR("Failed to allocate back buffer array memory.\n");
5667 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5668 return E_OUTOFMEMORY;
5673 if (swapchain->front_buffer != front_impl)
5675 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5677 if (swapchain->front_buffer)
5678 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5679 swapchain->front_buffer = front_impl;
5681 if (front_impl)
5682 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5685 if (swapchain->back_buffers[0] != back_impl)
5687 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5689 if (swapchain->back_buffers[0])
5690 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5691 swapchain->back_buffers[0] = back_impl;
5693 if (back_impl)
5695 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5696 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5697 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5698 swapchain->presentParms.BackBufferCount = 1;
5700 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5702 else
5704 swapchain->presentParms.BackBufferCount = 0;
5705 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5706 swapchain->back_buffers = NULL;
5710 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5711 return WINED3D_OK;
5714 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5716 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5718 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5720 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5721 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5722 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5723 IWineD3DSurface_AddRef(*depth_stencil);
5725 return WINED3D_OK;
5728 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5729 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5731 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5732 IWineD3DSurfaceImpl *prev;
5734 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5735 iface, render_target_idx, render_target, set_viewport);
5737 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5739 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5740 return WINED3DERR_INVALIDCALL;
5743 prev = device->render_targets[render_target_idx];
5744 if (render_target == (IWineD3DSurface *)prev)
5746 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5747 return WINED3D_OK;
5750 /* Render target 0 can't be set to NULL. */
5751 if (!render_target && !render_target_idx)
5753 WARN("Trying to set render target 0 to NULL.\n");
5754 return WINED3DERR_INVALIDCALL;
5757 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5759 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5760 return WINED3DERR_INVALIDCALL;
5763 if (render_target) IWineD3DSurface_AddRef(render_target);
5764 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5765 /* Release after the assignment, to prevent device_resource_released()
5766 * from seeing the surface as still in use. */
5767 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5769 /* Render target 0 is special. */
5770 if (!render_target_idx && set_viewport)
5772 /* Set the viewport and scissor rectangles, if requested. Tests show
5773 * that stateblock recording is ignored, the change goes directly
5774 * into the primary stateblock. */
5775 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5776 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5777 device->stateBlock->state.viewport.X = 0;
5778 device->stateBlock->state.viewport.Y = 0;
5779 device->stateBlock->state.viewport.MaxZ = 1.0f;
5780 device->stateBlock->state.viewport.MinZ = 0.0f;
5781 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5783 device->stateBlock->state.scissor_rect.top = 0;
5784 device->stateBlock->state.scissor_rect.left = 0;
5785 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5786 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5787 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5790 return WINED3D_OK;
5793 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5796 IWineD3DSurfaceImpl *tmp;
5798 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5800 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5802 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5803 return WINED3D_OK;
5806 if (This->depth_stencil)
5808 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5809 || This->depth_stencil->Flags & SFLAG_DISCARD)
5811 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5812 This->depth_stencil->currentDesc.Width,
5813 This->depth_stencil->currentDesc.Height);
5814 if (This->depth_stencil == This->onscreen_depth_stencil)
5816 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5817 This->onscreen_depth_stencil = NULL;
5822 tmp = This->depth_stencil;
5823 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5824 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5825 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5827 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5829 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5835 return WINED3D_OK;
5838 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5839 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5843 WINED3DLOCKED_RECT lockedRect;
5845 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5846 iface, XHotSpot, YHotSpot, cursor_image);
5848 /* some basic validation checks */
5849 if (This->cursorTexture)
5851 struct wined3d_context *context = context_acquire(This, NULL);
5852 ENTER_GL();
5853 glDeleteTextures(1, &This->cursorTexture);
5854 LEAVE_GL();
5855 context_release(context);
5856 This->cursorTexture = 0;
5859 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5860 This->haveHardwareCursor = TRUE;
5861 else
5862 This->haveHardwareCursor = FALSE;
5864 if (cursor_image)
5866 WINED3DLOCKED_RECT rect;
5868 /* MSDN: Cursor must be A8R8G8B8 */
5869 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5871 WARN("surface %p has an invalid format.\n", cursor_image);
5872 return WINED3DERR_INVALIDCALL;
5875 /* MSDN: Cursor must be smaller than the display mode */
5876 if (s->currentDesc.Width > This->ddraw_width
5877 || s->currentDesc.Height > This->ddraw_height)
5879 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5880 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5881 return WINED3DERR_INVALIDCALL;
5884 if (!This->haveHardwareCursor) {
5885 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5887 /* Do not store the surface's pointer because the application may
5888 * release it after setting the cursor image. Windows doesn't
5889 * addref the set surface, so we can't do this either without
5890 * creating circular refcount dependencies. Copy out the gl texture
5891 * instead.
5893 This->cursorWidth = s->currentDesc.Width;
5894 This->cursorHeight = s->currentDesc.Height;
5895 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5897 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5898 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5899 struct wined3d_context *context;
5900 char *mem, *bits = rect.pBits;
5901 GLint intfmt = format->glInternal;
5902 GLint gl_format = format->glFormat;
5903 GLint type = format->glType;
5904 INT height = This->cursorHeight;
5905 INT width = This->cursorWidth;
5906 INT bpp = format->byte_count;
5907 DWORD sampler;
5908 INT i;
5910 /* Reformat the texture memory (pitch and width can be
5911 * different) */
5912 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5913 for(i = 0; i < height; i++)
5914 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5915 IWineD3DSurface_UnlockRect(cursor_image);
5917 context = context_acquire(This, NULL);
5919 ENTER_GL();
5921 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5923 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5924 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5927 /* Make sure that a proper texture unit is selected */
5928 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5929 checkGLcall("glActiveTextureARB");
5930 sampler = This->rev_tex_unit_map[0];
5931 if (sampler != WINED3D_UNMAPPED_STAGE)
5933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5935 /* Create a new cursor texture */
5936 glGenTextures(1, &This->cursorTexture);
5937 checkGLcall("glGenTextures");
5938 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5939 checkGLcall("glBindTexture");
5940 /* Copy the bitmap memory into the cursor texture */
5941 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5942 HeapFree(GetProcessHeap(), 0, mem);
5943 checkGLcall("glTexImage2D");
5945 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5947 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5948 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5951 LEAVE_GL();
5953 context_release(context);
5955 else
5957 FIXME("A cursor texture was not returned.\n");
5958 This->cursorTexture = 0;
5961 else
5963 /* Draw a hardware cursor */
5964 ICONINFO cursorInfo;
5965 HCURSOR cursor;
5966 /* Create and clear maskBits because it is not needed for
5967 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5968 * chunks. */
5969 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5970 (s->currentDesc.Width * s->currentDesc.Height / 8));
5971 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5972 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5973 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5975 cursorInfo.fIcon = FALSE;
5976 cursorInfo.xHotspot = XHotSpot;
5977 cursorInfo.yHotspot = YHotSpot;
5978 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5979 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5980 IWineD3DSurface_UnlockRect(cursor_image);
5981 /* Create our cursor and clean up. */
5982 cursor = CreateIconIndirect(&cursorInfo);
5983 SetCursor(cursor);
5984 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5985 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5986 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5987 This->hardwareCursor = cursor;
5988 HeapFree(GetProcessHeap(), 0, maskBits);
5992 This->xHotSpot = XHotSpot;
5993 This->yHotSpot = YHotSpot;
5994 return WINED3D_OK;
5997 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5999 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6001 This->xScreenSpace = XScreenSpace;
6002 This->yScreenSpace = YScreenSpace;
6004 return;
6008 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6010 BOOL oldVisible = This->bCursorVisible;
6011 POINT pt;
6013 TRACE("(%p) : visible(%d)\n", This, bShow);
6016 * When ShowCursor is first called it should make the cursor appear at the OS's last
6017 * known cursor position. Because of this, some applications just repetitively call
6018 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6020 GetCursorPos(&pt);
6021 This->xScreenSpace = pt.x;
6022 This->yScreenSpace = pt.y;
6024 if (This->haveHardwareCursor) {
6025 This->bCursorVisible = bShow;
6026 if (bShow)
6027 SetCursor(This->hardwareCursor);
6028 else
6029 SetCursor(NULL);
6031 else
6033 if (This->cursorTexture)
6034 This->bCursorVisible = bShow;
6037 return oldVisible;
6040 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6041 TRACE("checking resource %p for eviction\n", resource);
6042 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6043 TRACE("Evicting %p\n", resource);
6044 IWineD3DResource_UnLoad(resource);
6046 IWineD3DResource_Release(resource);
6047 return S_OK;
6050 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6052 TRACE("iface %p.\n", iface);
6054 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6055 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6056 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6058 return WINED3D_OK;
6061 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6063 IWineD3DDeviceImpl *device = surface->resource.device;
6064 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6066 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6067 if(surface->Flags & SFLAG_DIBSECTION) {
6068 /* Release the DC */
6069 SelectObject(surface->hDC, surface->dib.holdbitmap);
6070 DeleteDC(surface->hDC);
6071 /* Release the DIB section */
6072 DeleteObject(surface->dib.DIBsection);
6073 surface->dib.bitmap_data = NULL;
6074 surface->resource.allocatedMemory = NULL;
6075 surface->Flags &= ~SFLAG_DIBSECTION;
6077 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6078 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6079 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6080 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6082 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6083 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6084 } else {
6085 surface->pow2Width = surface->pow2Height = 1;
6086 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6087 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6090 if (surface->texture_name)
6092 struct wined3d_context *context = context_acquire(device, NULL);
6093 ENTER_GL();
6094 glDeleteTextures(1, &surface->texture_name);
6095 LEAVE_GL();
6096 context_release(context);
6097 surface->texture_name = 0;
6098 surface->Flags &= ~SFLAG_CLIENT;
6100 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6101 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6102 surface->Flags |= SFLAG_NONPOW2;
6103 } else {
6104 surface->Flags &= ~SFLAG_NONPOW2;
6106 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6107 surface->resource.allocatedMemory = NULL;
6108 surface->resource.heapMemory = NULL;
6109 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6111 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6112 * to a FBO */
6113 if (!surface_init_sysmem(surface))
6115 return E_OUTOFMEMORY;
6117 return WINED3D_OK;
6120 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6121 TRACE("Unloading resource %p\n", resource);
6122 IWineD3DResource_UnLoad(resource);
6123 IWineD3DResource_Release(resource);
6124 return S_OK;
6127 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6129 UINT i, count;
6130 WINED3DDISPLAYMODE m;
6131 HRESULT hr;
6133 /* All Windowed modes are supported, as is leaving the current mode */
6134 if(pp->Windowed) return TRUE;
6135 if(!pp->BackBufferWidth) return TRUE;
6136 if(!pp->BackBufferHeight) return TRUE;
6138 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6139 for(i = 0; i < count; i++) {
6140 memset(&m, 0, sizeof(m));
6141 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6142 if(FAILED(hr)) {
6143 ERR("EnumAdapterModes failed\n");
6145 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6146 /* Mode found, it is supported */
6147 return TRUE;
6150 /* Mode not found -> not supported */
6151 return FALSE;
6154 /* Do not call while under the GL lock. */
6155 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6158 const struct wined3d_gl_info *gl_info;
6159 struct wined3d_context *context;
6160 IWineD3DBaseShaderImpl *shader;
6162 context = context_acquire(This, NULL);
6163 gl_info = context->gl_info;
6165 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6166 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6167 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6170 ENTER_GL();
6171 if(This->depth_blt_texture) {
6172 glDeleteTextures(1, &This->depth_blt_texture);
6173 This->depth_blt_texture = 0;
6175 if (This->depth_blt_rb) {
6176 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6177 This->depth_blt_rb = 0;
6178 This->depth_blt_rb_w = 0;
6179 This->depth_blt_rb_h = 0;
6181 LEAVE_GL();
6183 This->blitter->free_private(iface);
6184 This->frag_pipe->free_private(iface);
6185 This->shader_backend->shader_free_private(iface);
6186 destroy_dummy_textures(This, gl_info);
6188 context_release(context);
6190 while (This->numContexts)
6192 context_destroy(This, This->contexts[0]);
6194 HeapFree(GetProcessHeap(), 0, swapchain->context);
6195 swapchain->context = NULL;
6196 swapchain->num_contexts = 0;
6199 /* Do not call while under the GL lock. */
6200 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 struct wined3d_context *context;
6204 HRESULT hr;
6205 IWineD3DSurfaceImpl *target;
6207 /* Recreate the primary swapchain's context */
6208 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6209 if (!swapchain->context)
6211 ERR("Failed to allocate memory for swapchain context array.\n");
6212 return E_OUTOFMEMORY;
6215 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6216 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6218 WARN("Failed to create context.\n");
6219 HeapFree(GetProcessHeap(), 0, swapchain->context);
6220 return E_FAIL;
6223 swapchain->context[0] = context;
6224 swapchain->num_contexts = 1;
6225 create_dummy_textures(This);
6226 context_release(context);
6228 hr = This->shader_backend->shader_alloc_private(iface);
6229 if (FAILED(hr))
6231 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6232 goto err;
6235 hr = This->frag_pipe->alloc_private(iface);
6236 if (FAILED(hr))
6238 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6239 This->shader_backend->shader_free_private(iface);
6240 goto err;
6243 hr = This->blitter->alloc_private(iface);
6244 if (FAILED(hr))
6246 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6247 This->frag_pipe->free_private(iface);
6248 This->shader_backend->shader_free_private(iface);
6249 goto err;
6252 return WINED3D_OK;
6254 err:
6255 context_acquire(This, NULL);
6256 destroy_dummy_textures(This, context->gl_info);
6257 context_release(context);
6258 context_destroy(This, context);
6259 HeapFree(GetProcessHeap(), 0, swapchain->context);
6260 swapchain->num_contexts = 0;
6261 return hr;
6264 /* Do not call while under the GL lock. */
6265 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6266 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6269 IWineD3DSwapChainImpl *swapchain;
6270 HRESULT hr;
6271 BOOL DisplayModeChanged = FALSE;
6272 WINED3DDISPLAYMODE mode;
6273 TRACE("(%p)\n", This);
6275 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6276 if(FAILED(hr)) {
6277 ERR("Failed to get the first implicit swapchain\n");
6278 return hr;
6281 if(!is_display_mode_supported(This, pPresentationParameters)) {
6282 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6283 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6284 pPresentationParameters->BackBufferHeight);
6285 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6286 return WINED3DERR_INVALIDCALL;
6289 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6290 * on an existing gl context, so there's no real need for recreation.
6292 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6294 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6296 TRACE("New params:\n");
6297 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6298 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6299 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6300 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6301 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6302 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6303 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6304 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6305 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6306 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6307 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6308 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6309 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6311 /* No special treatment of these parameters. Just store them */
6312 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6313 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6314 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6315 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6317 /* What to do about these? */
6318 if (pPresentationParameters->BackBufferCount
6319 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6320 ERR("Cannot change the back buffer count yet\n");
6322 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6323 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6324 ERR("Cannot change the back buffer format yet\n");
6327 if (pPresentationParameters->hDeviceWindow
6328 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6329 ERR("Cannot change the device window yet\n");
6331 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6333 HRESULT hrc;
6335 TRACE("Creating the depth stencil buffer\n");
6337 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6338 pPresentationParameters->BackBufferWidth,
6339 pPresentationParameters->BackBufferHeight,
6340 pPresentationParameters->AutoDepthStencilFormat,
6341 pPresentationParameters->MultiSampleType,
6342 pPresentationParameters->MultiSampleQuality,
6343 FALSE,
6344 (IWineD3DSurface **)&This->auto_depth_stencil);
6346 if (FAILED(hrc)) {
6347 ERR("Failed to create the depth stencil buffer\n");
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6349 return WINED3DERR_INVALIDCALL;
6353 if (This->onscreen_depth_stencil)
6355 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6356 This->onscreen_depth_stencil = NULL;
6359 /* Reset the depth stencil */
6360 if (pPresentationParameters->EnableAutoDepthStencil)
6361 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6362 else
6363 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6365 TRACE("Resetting stateblock\n");
6366 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6367 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6369 delete_opengl_contexts(iface, swapchain);
6371 if(pPresentationParameters->Windowed) {
6372 mode.Width = swapchain->orig_width;
6373 mode.Height = swapchain->orig_height;
6374 mode.RefreshRate = 0;
6375 mode.Format = swapchain->presentParms.BackBufferFormat;
6376 } else {
6377 mode.Width = pPresentationParameters->BackBufferWidth;
6378 mode.Height = pPresentationParameters->BackBufferHeight;
6379 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6380 mode.Format = swapchain->presentParms.BackBufferFormat;
6383 /* Should Width == 800 && Height == 0 set 800x600? */
6384 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6385 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6386 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6388 UINT i;
6390 if(!pPresentationParameters->Windowed) {
6391 DisplayModeChanged = TRUE;
6393 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6394 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6396 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6397 if(FAILED(hr))
6399 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6400 return hr;
6403 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6405 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6406 if(FAILED(hr))
6408 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6409 return hr;
6412 if (This->auto_depth_stencil)
6414 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6415 if(FAILED(hr))
6417 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6418 return hr;
6423 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6424 || DisplayModeChanged)
6426 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6428 if (!pPresentationParameters->Windowed)
6430 if(swapchain->presentParms.Windowed) {
6431 /* switch from windowed to fs */
6432 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6433 pPresentationParameters->BackBufferHeight);
6434 } else {
6435 /* Fullscreen -> fullscreen mode change */
6436 MoveWindow(swapchain->device_window, 0, 0,
6437 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6438 TRUE);
6441 else if (!swapchain->presentParms.Windowed)
6443 /* Fullscreen -> windowed switch */
6444 swapchain_restore_fullscreen_window(swapchain);
6446 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6447 } else if(!pPresentationParameters->Windowed) {
6448 DWORD style = This->style, exStyle = This->exStyle;
6449 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6450 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6451 * Reset to clear up their mess. Guild Wars also loses the device during that.
6453 This->style = 0;
6454 This->exStyle = 0;
6455 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6456 pPresentationParameters->BackBufferHeight);
6457 This->style = style;
6458 This->exStyle = exStyle;
6461 /* Note: No parent needed for initial internal stateblock */
6462 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6463 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6464 else TRACE("Created stateblock %p\n", This->stateBlock);
6465 This->updateStateBlock = This->stateBlock;
6466 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6468 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6469 if(FAILED(hr)) {
6470 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6473 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6475 RECT client_rect;
6476 GetClientRect(swapchain->win_handle, &client_rect);
6478 if(!swapchain->presentParms.BackBufferCount)
6480 TRACE("Single buffered rendering\n");
6481 swapchain->render_to_fbo = FALSE;
6483 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6484 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6486 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6487 swapchain->presentParms.BackBufferWidth,
6488 swapchain->presentParms.BackBufferHeight,
6489 client_rect.right, client_rect.bottom);
6490 swapchain->render_to_fbo = TRUE;
6492 else
6494 TRACE("Rendering directly to GL_BACK\n");
6495 swapchain->render_to_fbo = FALSE;
6499 hr = create_primary_opengl_context(iface, swapchain);
6500 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6502 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6503 * first use
6505 return hr;
6508 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6510 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6512 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6514 return WINED3D_OK;
6518 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6520 TRACE("(%p) : pParameters %p\n", This, pParameters);
6522 *pParameters = This->createParms;
6523 return WINED3D_OK;
6526 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6527 IWineD3DSwapChain *swapchain;
6529 TRACE("Relaying to swapchain\n");
6531 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6532 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6533 IWineD3DSwapChain_Release(swapchain);
6537 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6538 IWineD3DSwapChain *swapchain;
6540 TRACE("Relaying to swapchain\n");
6542 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6543 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6544 IWineD3DSwapChain_Release(swapchain);
6549 /** ********************************************************
6550 * Notification functions
6551 ** ********************************************************/
6552 /** This function must be called in the release of a resource when ref == 0,
6553 * the contents of resource must still be correct,
6554 * any handles to other resource held by the caller must be closed
6555 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6556 *****************************************************/
6557 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6559 TRACE("(%p) : Adding resource %p\n", This, resource);
6561 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6564 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6566 TRACE("(%p) : Removing resource %p\n", This, resource);
6568 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6571 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6573 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6574 unsigned int i;
6576 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6578 context_resource_released(device, resource, type);
6580 switch (type)
6582 case WINED3DRTYPE_SURFACE:
6583 if (!device->d3d_initialized) break;
6585 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6587 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6589 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6590 device->render_targets[i] = NULL;
6594 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6596 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6597 device->depth_stencil = NULL;
6599 break;
6601 case WINED3DRTYPE_TEXTURE:
6602 case WINED3DRTYPE_CUBETEXTURE:
6603 case WINED3DRTYPE_VOLUMETEXTURE:
6604 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6606 if (device->stateBlock && device->stateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6608 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6609 resource, device->stateBlock, i);
6610 device->stateBlock->state.textures[i] = NULL;
6613 if (device->updateStateBlock != device->stateBlock
6614 && device->updateStateBlock->state.textures[i] == (IWineD3DBaseTextureImpl *)resource)
6616 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6617 resource, device->updateStateBlock, i);
6618 device->updateStateBlock->state.textures[i] = NULL;
6621 break;
6623 case WINED3DRTYPE_BUFFER:
6624 for (i = 0; i < MAX_STREAMS; ++i)
6626 if (device->stateBlock
6627 && device->stateBlock->state.streams[i].buffer == (struct wined3d_buffer *)resource)
6629 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6630 resource, device->stateBlock, i);
6631 device->stateBlock->state.streams[i].buffer = NULL;
6634 if (device->updateStateBlock != device->stateBlock
6635 && device->updateStateBlock->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->updateStateBlock, i);
6639 device->updateStateBlock->state.streams[i].buffer = NULL;
6644 if (device->stateBlock && device->stateBlock->state.index_buffer == (struct wined3d_buffer *)resource)
6646 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6647 resource, device->stateBlock);
6648 device->stateBlock->state.index_buffer = NULL;
6651 if (device->updateStateBlock != device->stateBlock
6652 && device->updateStateBlock->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->updateStateBlock);
6656 device->updateStateBlock->state.index_buffer = NULL;
6658 break;
6660 default:
6661 break;
6664 /* Remove the resource from the resourceStore */
6665 device_resource_remove(device, resource);
6667 TRACE("Resource released.\n");
6670 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6672 IWineD3DResourceImpl *resource, *cursor;
6673 HRESULT ret;
6674 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6676 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6677 TRACE("enumerating resource %p\n", resource);
6678 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6679 ret = pCallback((IWineD3DResource *) resource, pData);
6680 if(ret == S_FALSE) {
6681 TRACE("Canceling enumeration\n");
6682 break;
6685 return WINED3D_OK;
6688 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6691 IWineD3DResourceImpl *resource;
6693 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6695 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6696 if (type == WINED3DRTYPE_SURFACE)
6698 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6700 TRACE("Found surface %p for dc %p.\n", resource, dc);
6701 *surface = (IWineD3DSurface *)resource;
6702 return WINED3D_OK;
6707 return WINED3DERR_INVALIDCALL;
6710 /**********************************************************
6711 * IWineD3DDevice VTbl follows
6712 **********************************************************/
6714 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6716 /*** IUnknown methods ***/
6717 IWineD3DDeviceImpl_QueryInterface,
6718 IWineD3DDeviceImpl_AddRef,
6719 IWineD3DDeviceImpl_Release,
6720 /*** IWineD3DDevice methods ***/
6721 /*** Creation methods**/
6722 IWineD3DDeviceImpl_CreateBuffer,
6723 IWineD3DDeviceImpl_CreateVertexBuffer,
6724 IWineD3DDeviceImpl_CreateIndexBuffer,
6725 IWineD3DDeviceImpl_CreateStateBlock,
6726 IWineD3DDeviceImpl_CreateSurface,
6727 IWineD3DDeviceImpl_CreateRendertargetView,
6728 IWineD3DDeviceImpl_CreateTexture,
6729 IWineD3DDeviceImpl_CreateVolumeTexture,
6730 IWineD3DDeviceImpl_CreateVolume,
6731 IWineD3DDeviceImpl_CreateCubeTexture,
6732 IWineD3DDeviceImpl_CreateQuery,
6733 IWineD3DDeviceImpl_CreateSwapChain,
6734 IWineD3DDeviceImpl_CreateVertexDeclaration,
6735 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6736 IWineD3DDeviceImpl_CreateVertexShader,
6737 IWineD3DDeviceImpl_CreateGeometryShader,
6738 IWineD3DDeviceImpl_CreatePixelShader,
6739 IWineD3DDeviceImpl_CreatePalette,
6740 /*** Odd functions **/
6741 IWineD3DDeviceImpl_Init3D,
6742 IWineD3DDeviceImpl_InitGDI,
6743 IWineD3DDeviceImpl_Uninit3D,
6744 IWineD3DDeviceImpl_UninitGDI,
6745 IWineD3DDeviceImpl_SetMultithreaded,
6746 IWineD3DDeviceImpl_EvictManagedResources,
6747 IWineD3DDeviceImpl_GetAvailableTextureMem,
6748 IWineD3DDeviceImpl_GetBackBuffer,
6749 IWineD3DDeviceImpl_GetCreationParameters,
6750 IWineD3DDeviceImpl_GetDeviceCaps,
6751 IWineD3DDeviceImpl_GetDirect3D,
6752 IWineD3DDeviceImpl_GetDisplayMode,
6753 IWineD3DDeviceImpl_SetDisplayMode,
6754 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6755 IWineD3DDeviceImpl_GetRasterStatus,
6756 IWineD3DDeviceImpl_GetSwapChain,
6757 IWineD3DDeviceImpl_Reset,
6758 IWineD3DDeviceImpl_SetDialogBoxMode,
6759 IWineD3DDeviceImpl_SetCursorProperties,
6760 IWineD3DDeviceImpl_SetCursorPosition,
6761 IWineD3DDeviceImpl_ShowCursor,
6762 /*** Getters and setters **/
6763 IWineD3DDeviceImpl_SetClipPlane,
6764 IWineD3DDeviceImpl_GetClipPlane,
6765 IWineD3DDeviceImpl_SetClipStatus,
6766 IWineD3DDeviceImpl_GetClipStatus,
6767 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6768 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6769 IWineD3DDeviceImpl_SetDepthStencilSurface,
6770 IWineD3DDeviceImpl_GetDepthStencilSurface,
6771 IWineD3DDeviceImpl_SetGammaRamp,
6772 IWineD3DDeviceImpl_GetGammaRamp,
6773 IWineD3DDeviceImpl_SetIndexBuffer,
6774 IWineD3DDeviceImpl_GetIndexBuffer,
6775 IWineD3DDeviceImpl_SetBaseVertexIndex,
6776 IWineD3DDeviceImpl_GetBaseVertexIndex,
6777 IWineD3DDeviceImpl_SetLight,
6778 IWineD3DDeviceImpl_GetLight,
6779 IWineD3DDeviceImpl_SetLightEnable,
6780 IWineD3DDeviceImpl_GetLightEnable,
6781 IWineD3DDeviceImpl_SetMaterial,
6782 IWineD3DDeviceImpl_GetMaterial,
6783 IWineD3DDeviceImpl_SetNPatchMode,
6784 IWineD3DDeviceImpl_GetNPatchMode,
6785 IWineD3DDeviceImpl_SetPaletteEntries,
6786 IWineD3DDeviceImpl_GetPaletteEntries,
6787 IWineD3DDeviceImpl_SetPixelShader,
6788 IWineD3DDeviceImpl_GetPixelShader,
6789 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6790 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6791 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6792 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6793 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6794 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6795 IWineD3DDeviceImpl_SetRenderState,
6796 IWineD3DDeviceImpl_GetRenderState,
6797 IWineD3DDeviceImpl_SetRenderTarget,
6798 IWineD3DDeviceImpl_GetRenderTarget,
6799 IWineD3DDeviceImpl_SetFrontBackBuffers,
6800 IWineD3DDeviceImpl_SetSamplerState,
6801 IWineD3DDeviceImpl_GetSamplerState,
6802 IWineD3DDeviceImpl_SetScissorRect,
6803 IWineD3DDeviceImpl_GetScissorRect,
6804 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6805 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6806 IWineD3DDeviceImpl_SetStreamSource,
6807 IWineD3DDeviceImpl_GetStreamSource,
6808 IWineD3DDeviceImpl_SetStreamSourceFreq,
6809 IWineD3DDeviceImpl_GetStreamSourceFreq,
6810 IWineD3DDeviceImpl_SetTexture,
6811 IWineD3DDeviceImpl_GetTexture,
6812 IWineD3DDeviceImpl_SetTextureStageState,
6813 IWineD3DDeviceImpl_GetTextureStageState,
6814 IWineD3DDeviceImpl_SetTransform,
6815 IWineD3DDeviceImpl_GetTransform,
6816 IWineD3DDeviceImpl_SetVertexDeclaration,
6817 IWineD3DDeviceImpl_GetVertexDeclaration,
6818 IWineD3DDeviceImpl_SetVertexShader,
6819 IWineD3DDeviceImpl_GetVertexShader,
6820 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6821 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6822 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6823 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6824 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6825 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6826 IWineD3DDeviceImpl_SetViewport,
6827 IWineD3DDeviceImpl_GetViewport,
6828 IWineD3DDeviceImpl_MultiplyTransform,
6829 IWineD3DDeviceImpl_ValidateDevice,
6830 IWineD3DDeviceImpl_ProcessVertices,
6831 /*** State block ***/
6832 IWineD3DDeviceImpl_BeginStateBlock,
6833 IWineD3DDeviceImpl_EndStateBlock,
6834 /*** Scene management ***/
6835 IWineD3DDeviceImpl_BeginScene,
6836 IWineD3DDeviceImpl_EndScene,
6837 IWineD3DDeviceImpl_Present,
6838 IWineD3DDeviceImpl_Clear,
6839 IWineD3DDeviceImpl_ClearRendertargetView,
6840 /*** Drawing ***/
6841 IWineD3DDeviceImpl_SetPrimitiveType,
6842 IWineD3DDeviceImpl_GetPrimitiveType,
6843 IWineD3DDeviceImpl_DrawPrimitive,
6844 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6845 IWineD3DDeviceImpl_DrawPrimitiveUP,
6846 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6847 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6848 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6849 IWineD3DDeviceImpl_DrawRectPatch,
6850 IWineD3DDeviceImpl_DrawTriPatch,
6851 IWineD3DDeviceImpl_DeletePatch,
6852 IWineD3DDeviceImpl_ColorFill,
6853 IWineD3DDeviceImpl_UpdateTexture,
6854 IWineD3DDeviceImpl_UpdateSurface,
6855 IWineD3DDeviceImpl_GetFrontBufferData,
6856 /*** object tracking ***/
6857 IWineD3DDeviceImpl_EnumResources,
6858 IWineD3DDeviceImpl_GetSurfaceFromDC,
6859 IWineD3DDeviceImpl_AcquireFocusWindow,
6860 IWineD3DDeviceImpl_ReleaseFocusWindow,
6863 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6864 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6865 IWineD3DDeviceParent *device_parent)
6867 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6868 const struct fragment_pipeline *fragment_pipeline;
6869 struct shader_caps shader_caps;
6870 struct fragment_caps ffp_caps;
6871 WINED3DDISPLAYMODE mode;
6872 unsigned int i;
6873 HRESULT hr;
6875 device->lpVtbl = &IWineD3DDevice_Vtbl;
6876 device->ref = 1;
6877 device->wined3d = (IWineD3D *)wined3d;
6878 IWineD3D_AddRef(device->wined3d);
6879 device->adapter = wined3d->adapter_count ? adapter : NULL;
6880 device->device_parent = device_parent;
6881 list_init(&device->resources);
6882 list_init(&device->shaders);
6884 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6885 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6887 /* Get the initial screen setup for ddraw. */
6888 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6889 if (FAILED(hr))
6891 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6892 IWineD3D_Release(device->wined3d);
6893 return hr;
6895 device->ddraw_width = mode.Width;
6896 device->ddraw_height = mode.Height;
6897 device->ddraw_format = mode.Format;
6899 /* Save the creation parameters. */
6900 device->createParms.AdapterOrdinal = adapter_idx;
6901 device->createParms.DeviceType = device_type;
6902 device->createParms.hFocusWindow = focus_window;
6903 device->createParms.BehaviorFlags = flags;
6905 device->devType = device_type;
6906 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6908 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6909 device->shader_backend = adapter->shader_backend;
6911 if (device->shader_backend)
6913 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6914 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6915 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6916 device->vs_clipping = shader_caps.VSClipping;
6918 fragment_pipeline = adapter->fragment_pipe;
6919 device->frag_pipe = fragment_pipeline;
6920 if (fragment_pipeline)
6922 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6923 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6925 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6926 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6927 if (FAILED(hr))
6929 ERR("Failed to compile state table, hr %#x.\n", hr);
6930 IWineD3D_Release(device->wined3d);
6931 return hr;
6934 device->blitter = adapter->blitter;
6936 return WINED3D_OK;
6940 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6941 DWORD rep = This->StateTable[state].representative;
6942 struct wined3d_context *context;
6943 DWORD idx;
6944 BYTE shift;
6945 UINT i;
6947 for(i = 0; i < This->numContexts; i++) {
6948 context = This->contexts[i];
6949 if(isStateDirty(context, rep)) continue;
6951 context->dirtyArray[context->numDirtyEntries++] = rep;
6952 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6953 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6954 context->isStateDirty[idx] |= (1 << shift);
6958 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6960 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6961 *width = context->current_rt->pow2Width;
6962 *height = context->current_rt->pow2Height;
6965 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6967 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6968 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6969 * current context's drawable, which is the size of the back buffer of the swapchain
6970 * the active context belongs to. */
6971 *width = swapchain->presentParms.BackBufferWidth;
6972 *height = swapchain->presentParms.BackBufferHeight;
6975 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6976 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6978 if (device->filter_messages)
6980 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6981 window, message, wparam, lparam);
6982 return DefWindowProcW(window, message, wparam, lparam);
6985 if (message == WM_DESTROY)
6987 TRACE("unregister window %p.\n", window);
6988 wined3d_unregister_window(window);
6990 if (device->focus_window == window) device->focus_window = NULL;
6991 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6994 return CallWindowProcW(proc, window, message, wparam, lparam);