wined3d: Fix context_apply_clear_state with ORM = backbuffer.
[wine.git] / dlls / wined3d / device.c
blobff9bd00436552ad4e7b43ee932524dd9cd540b8b
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 == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
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 = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
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 GLuint buffer_object = 0;
195 const BYTE *data = NULL;
196 BOOL stride_used;
197 unsigned int idx;
198 DWORD stride;
200 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201 element, i + 1, declaration->element_count);
203 if (!This->stateBlock->streamSource[element->input_slot]) continue;
205 stride = This->stateBlock->streamStride[element->input_slot];
206 if (This->stateBlock->streamIsUP)
208 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
209 buffer_object = 0;
210 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
212 else
214 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
215 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot],
216 &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((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot],
228 &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 warned = TRUE;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
278 stride_used = FALSE;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->streamIsUP)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
319 struct wined3d_event_query *query;
321 if (!(map & 1)) continue;
323 element = &stream_info->elements[i];
324 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
325 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
327 /* If PreLoad dropped the buffer object, update the stream info. */
328 if (buffer->buffer_object != element->buffer_object)
330 element->buffer_object = 0;
331 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 query = ((struct wined3d_buffer *) buffer)->query;
335 if(query)
337 This->buffer_queries[This->num_buffer_queries++] = query;
343 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
344 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
346 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
347 e->format_desc = format_desc;
348 e->stride = strided->dwStride;
349 e->data = strided->lpData;
350 e->stream_idx = 0;
351 e->buffer_object = 0;
354 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
355 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
357 unsigned int i;
359 memset(stream_info, 0, sizeof(*stream_info));
361 if (strided->position.lpData)
362 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
363 if (strided->normal.lpData)
364 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
365 if (strided->diffuse.lpData)
366 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
367 if (strided->specular.lpData)
368 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
370 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
372 if (strided->texCoords[i].lpData)
373 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
374 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
377 stream_info->position_transformed = strided->position_transformed;
379 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
381 if (!stream_info->elements[i].format_desc) continue;
383 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
384 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
386 stream_info->swizzle_map |= 1 << i;
388 stream_info->use_map |= 1 << i;
392 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
394 TRACE("Strided Data:\n");
395 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
412 /* Context activation is done by the caller. */
413 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
415 struct wined3d_stream_info *stream_info = &device->strided_streams;
416 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
417 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
418 BOOL fixup = FALSE;
420 if (device->up_strided)
422 /* Note: this is a ddraw fixed-function code path. */
423 TRACE("=============================== Strided Input ================================\n");
424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
427 else
429 TRACE("============================= Vertex Declaration =============================\n");
430 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
433 if (vs && !stream_info->position_transformed)
435 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
438 device->useDrawStridedSlow = TRUE;
440 else
442 device->useDrawStridedSlow = FALSE;
445 else
447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
453 device->useDrawStridedSlow = TRUE;
455 else
457 device->useDrawStridedSlow = FALSE;
462 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
464 IWineD3DBaseTextureImpl *texture;
465 enum WINED3DSRGB srgb;
467 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
468 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
469 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
472 void device_preload_textures(IWineD3DDeviceImpl *device)
474 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
475 unsigned int i;
477 if (use_vs(stateblock))
479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
486 if (use_ps(stateblock))
488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
490 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
491 device_preload_texture(stateblock, i);
494 else
496 WORD ffu_map = device->fixed_function_usage_map;
498 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
500 if (ffu_map & 1)
501 device_preload_texture(stateblock, i);
506 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
508 struct wined3d_context **new_array;
510 TRACE("Adding context %p.\n", context);
512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
515 if (!new_array)
517 ERR("Failed to grow the context array.\n");
518 return FALSE;
521 new_array[device->numContexts++] = context;
522 device->contexts = new_array;
523 return TRUE;
526 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
528 struct wined3d_context **new_array;
529 BOOL found = FALSE;
530 UINT i;
532 TRACE("Removing context %p.\n", context);
534 for (i = 0; i < device->numContexts; ++i)
536 if (device->contexts[i] == context)
538 found = TRUE;
539 break;
543 if (!found)
545 ERR("Context %p doesn't exist in context array.\n", context);
546 return;
549 if (!--device->numContexts)
551 HeapFree(GetProcessHeap(), 0, device->contexts);
552 device->contexts = NULL;
553 return;
556 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
557 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
558 if (!new_array)
560 ERR("Failed to shrink context array. Oh well.\n");
561 return;
564 device->contexts = new_array;
567 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
569 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
570 WINED3DVIEWPORT *vp = &stateblock->viewport;
572 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
574 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
576 IntersectRect(rect, rect, &stateblock->scissorRect);
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
597 /* partial draw rect */
598 if (draw_rect->left || draw_rect->top
599 || draw_rect->right < target->currentDesc.Width
600 || draw_rect->bottom < target->currentDesc.Height)
601 return FALSE;
603 /* partial clear rect */
604 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
605 || clear_rect->right < target->currentDesc.Width
606 || clear_rect->bottom < target->currentDesc.Height))
607 return FALSE;
609 return TRUE;
612 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
613 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
615 RECT current_rect, r;
617 if (ds->Flags & location)
618 SetRect(&current_rect, 0, 0,
619 ds->ds_current_size.cx,
620 ds->ds_current_size.cy);
621 else
622 SetRectEmpty(&current_rect);
624 IntersectRect(&r, draw_rect, &current_rect);
625 if (EqualRect(&r, draw_rect))
627 /* current_rect ⊇ draw_rect, modify only. */
628 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
629 return;
632 if (EqualRect(&r, &current_rect))
634 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
636 if (!clear_rect)
638 /* Full clear, modify only. */
639 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
640 return;
643 IntersectRect(&r, draw_rect, clear_rect);
644 if (EqualRect(&r, draw_rect))
646 /* clear_rect ⊇ draw_rect, modify only. */
647 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
648 return;
652 /* Full load. */
653 surface_load_ds_location(ds, context, location);
654 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
657 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
658 UINT rect_count, const WINED3DRECT *rects, DWORD flags, const float color[4], float depth, DWORD stencil)
660 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
661 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
662 IWineD3DSurfaceImpl *target = rts[0];
663 UINT drawable_width, drawable_height;
664 struct wined3d_context *context;
665 GLbitfield clear_mask = 0;
666 unsigned int i;
667 RECT draw_rect;
669 device_get_draw_rect(device, &draw_rect);
671 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
672 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
673 * for the cleared parts, and the untouched parts.
675 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
676 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
677 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
678 * checking all this if the dest surface is in the drawable anyway. */
679 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, &draw_rect, clear_rect))
681 for (i = 0; i < rt_count; ++i)
683 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
687 context = context_acquire(device, target);
688 if (!context->valid)
690 context_release(context);
691 WARN("Invalid context, skipping clear.\n");
692 return WINED3D_OK;
695 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
697 target->get_drawable_size(context, &drawable_width, &drawable_height);
699 ENTER_GL();
701 /* Only set the values up once, as they are not changing. */
702 if (flags & WINED3DCLEAR_STENCIL)
704 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
706 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
707 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
709 glStencilMask(~0U);
710 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
711 glClearStencil(stencil);
712 checkGLcall("glClearStencil");
713 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
716 if (flags & WINED3DCLEAR_ZBUFFER)
718 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
720 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
721 device_switch_onscreen_ds(device, context, depth_stencil);
722 prepare_ds_clear(depth_stencil, context, location, &draw_rect, rect_count, clear_rect);
723 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
725 glDepthMask(GL_TRUE);
726 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
727 glClearDepth(depth);
728 checkGLcall("glClearDepth");
729 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
732 if (flags & WINED3DCLEAR_TARGET)
734 for (i = 0; i < rt_count; ++i)
736 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
739 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
742 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
743 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
744 glClearColor(color[0], color[1], color[2], color[3]);
745 checkGLcall("glClearColor");
746 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (!clear_rect)
751 if (context->render_offscreen)
753 glScissor(draw_rect.left, draw_rect.top,
754 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
756 else
758 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
759 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
761 checkGLcall("glScissor");
762 glClear(clear_mask);
763 checkGLcall("glClear");
765 else
767 RECT current_rect;
769 /* Now process each rect in turn. */
770 for (i = 0; i < rect_count; ++i)
772 /* Note that GL uses lower left, width/height. */
773 IntersectRect(&current_rect, &draw_rect, &clear_rect[i]);
775 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
776 wine_dbgstr_rect(&clear_rect[i]),
777 wine_dbgstr_rect(&current_rect));
779 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
780 * The rectangle is not cleared, no error is returned, but further rectanlges are
781 * still cleared if they are valid. */
782 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
784 TRACE("Rectangle with negative dimensions, ignoring.\n");
785 continue;
788 if (context->render_offscreen)
790 glScissor(current_rect.left, current_rect.top,
791 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 else
795 glScissor(current_rect.left, drawable_height - current_rect.bottom,
796 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
798 checkGLcall("glScissor");
800 glClear(clear_mask);
801 checkGLcall("glClear");
805 LEAVE_GL();
807 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
808 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
809 wglFlush(); /* Flush to ensure ordering across contexts. */
811 context_release(context);
813 return WINED3D_OK;
817 /**********************************************************
818 * IUnknown parts follows
819 **********************************************************/
821 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
825 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
826 if (IsEqualGUID(riid, &IID_IUnknown)
827 || IsEqualGUID(riid, &IID_IWineD3DBase)
828 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
829 IUnknown_AddRef(iface);
830 *ppobj = This;
831 return S_OK;
833 *ppobj = 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 /**********************************************************
890 * IWineD3DDevice implementation follows
891 **********************************************************/
892 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
894 *pParent = This->parent;
895 IUnknown_AddRef(This->parent);
896 return WINED3D_OK;
899 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
900 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
903 struct wined3d_buffer *object;
904 HRESULT hr;
906 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
908 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
909 if (!object)
911 ERR("Failed to allocate memory\n");
912 return E_OUTOFMEMORY;
915 FIXME("Ignoring access flags (pool)\n");
917 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
918 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
919 if (FAILED(hr))
921 WARN("Failed to initialize buffer, hr %#x.\n", hr);
922 HeapFree(GetProcessHeap(), 0, object);
923 return hr;
925 object->desc = *desc;
927 TRACE("Created buffer %p.\n", object);
929 *buffer = (IWineD3DBuffer *)object;
931 return WINED3D_OK;
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
935 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
936 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
939 struct wined3d_buffer *object;
940 HRESULT hr;
942 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
943 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
945 if (Pool == WINED3DPOOL_SCRATCH)
947 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
948 * anyway, SCRATCH vertex buffers aren't usable anywhere
950 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
951 *ppVertexBuffer = NULL;
952 return WINED3DERR_INVALIDCALL;
955 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
956 if (!object)
958 ERR("Out of memory\n");
959 *ppVertexBuffer = NULL;
960 return WINED3DERR_OUTOFVIDEOMEMORY;
963 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
964 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
965 if (FAILED(hr))
967 WARN("Failed to initialize buffer, hr %#x.\n", hr);
968 HeapFree(GetProcessHeap(), 0, object);
969 return hr;
972 TRACE("Created buffer %p.\n", object);
973 *ppVertexBuffer = (IWineD3DBuffer *)object;
975 return WINED3D_OK;
978 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
979 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
980 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 struct wined3d_buffer *object;
984 HRESULT hr;
986 TRACE("(%p) Creating index buffer\n", This);
988 /* Allocate the storage for the device */
989 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
990 if (!object)
992 ERR("Out of memory\n");
993 *ppIndexBuffer = NULL;
994 return WINED3DERR_OUTOFVIDEOMEMORY;
997 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
998 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
999 parent, parent_ops);
1000 if (FAILED(hr))
1002 WARN("Failed to initialize buffer, hr %#x\n", hr);
1003 HeapFree(GetProcessHeap(), 0, object);
1004 return hr;
1007 TRACE("Created buffer %p.\n", object);
1009 *ppIndexBuffer = (IWineD3DBuffer *) object;
1011 return WINED3D_OK;
1014 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1015 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1018 IWineD3DStateBlockImpl *object;
1019 HRESULT hr;
1021 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1022 if(!object)
1024 ERR("Failed to allocate stateblock memory.\n");
1025 return E_OUTOFMEMORY;
1028 hr = stateblock_init(object, This, type);
1029 if (FAILED(hr))
1031 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1032 HeapFree(GetProcessHeap(), 0, object);
1033 return hr;
1036 TRACE("Created stateblock %p.\n", object);
1037 *stateblock = (IWineD3DStateBlock *)object;
1039 return WINED3D_OK;
1042 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1043 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **surface,
1044 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
1045 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048 IWineD3DSurfaceImpl *object;
1049 HRESULT hr;
1051 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1052 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1053 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1054 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1055 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1057 if (Impl == SURFACE_OPENGL && !This->adapter)
1059 ERR("OpenGL surfaces are not available without OpenGL.\n");
1060 return WINED3DERR_NOTAVAILABLE;
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 if (!object)
1066 ERR("Failed to allocate surface memory.\n");
1067 return WINED3DERR_OUTOFVIDEOMEMORY;
1070 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1071 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1072 if (FAILED(hr))
1074 WARN("Failed to initialize surface, returning %#x.\n", hr);
1075 HeapFree(GetProcessHeap(), 0, object);
1076 return hr;
1079 TRACE("(%p) : Created surface %p\n", This, object);
1081 *surface = (IWineD3DSurface *)object;
1083 return hr;
1086 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1087 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1089 struct wined3d_rendertarget_view *object;
1091 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1092 iface, resource, parent, rendertarget_view);
1094 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1095 if (!object)
1097 ERR("Failed to allocate memory\n");
1098 return E_OUTOFMEMORY;
1101 wined3d_rendertarget_view_init(object, resource, parent);
1103 TRACE("Created render target view %p.\n", object);
1104 *rendertarget_view = (IWineD3DRendertargetView *)object;
1106 return WINED3D_OK;
1109 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1110 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1111 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1114 IWineD3DTextureImpl *object;
1115 HRESULT hr;
1117 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1118 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1119 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1121 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1122 if (!object)
1124 ERR("Out of memory\n");
1125 *ppTexture = NULL;
1126 return WINED3DERR_OUTOFVIDEOMEMORY;
1129 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1130 if (FAILED(hr))
1132 WARN("Failed to initialize texture, returning %#x\n", hr);
1133 HeapFree(GetProcessHeap(), 0, object);
1134 *ppTexture = NULL;
1135 return hr;
1138 *ppTexture = (IWineD3DTexture *)object;
1140 TRACE("(%p) : Created texture %p\n", This, object);
1142 return WINED3D_OK;
1145 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1146 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1147 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1150 IWineD3DVolumeTextureImpl *object;
1151 HRESULT hr;
1153 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1154 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1156 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1157 if (!object)
1159 ERR("Out of memory\n");
1160 *ppVolumeTexture = NULL;
1161 return WINED3DERR_OUTOFVIDEOMEMORY;
1164 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1165 if (FAILED(hr))
1167 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1168 HeapFree(GetProcessHeap(), 0, object);
1169 *ppVolumeTexture = NULL;
1170 return hr;
1173 TRACE("(%p) : Created volume texture %p.\n", This, object);
1174 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1176 return WINED3D_OK;
1179 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1180 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1181 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1184 IWineD3DVolumeImpl *object;
1185 HRESULT hr;
1187 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1188 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1190 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1191 if (!object)
1193 ERR("Out of memory\n");
1194 *ppVolume = NULL;
1195 return WINED3DERR_OUTOFVIDEOMEMORY;
1198 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1199 if (FAILED(hr))
1201 WARN("Failed to initialize volume, returning %#x.\n", hr);
1202 HeapFree(GetProcessHeap(), 0, object);
1203 return hr;
1206 TRACE("(%p) : Created volume %p.\n", This, object);
1207 *ppVolume = (IWineD3DVolume *)object;
1209 return WINED3D_OK;
1212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1213 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1214 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1217 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1218 HRESULT hr;
1220 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1221 if (!object)
1223 ERR("Out of memory\n");
1224 *ppCubeTexture = NULL;
1225 return WINED3DERR_OUTOFVIDEOMEMORY;
1228 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1229 if (FAILED(hr))
1231 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1232 HeapFree(GetProcessHeap(), 0, object);
1233 *ppCubeTexture = NULL;
1234 return hr;
1237 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1238 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1240 return WINED3D_OK;
1243 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1244 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1247 IWineD3DQueryImpl *object;
1248 HRESULT hr;
1250 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1252 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1253 if (!object)
1255 ERR("Failed to allocate query memory.\n");
1256 return E_OUTOFMEMORY;
1259 hr = query_init(object, This, type, parent);
1260 if (FAILED(hr))
1262 WARN("Failed to initialize query, hr %#x.\n", hr);
1263 HeapFree(GetProcessHeap(), 0, object);
1264 return hr;
1267 TRACE("Created query %p.\n", object);
1268 *query = (IWineD3DQuery *)object;
1270 return WINED3D_OK;
1273 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1274 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1275 IUnknown *parent, WINED3DSURFTYPE surface_type)
1277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1278 IWineD3DSwapChainImpl *object;
1279 HRESULT hr;
1281 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1282 iface, present_parameters, swapchain, parent, surface_type);
1284 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1285 if (!object)
1287 ERR("Failed to allocate swapchain memory.\n");
1288 return E_OUTOFMEMORY;
1291 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1292 if (FAILED(hr))
1294 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1295 HeapFree(GetProcessHeap(), 0, object);
1296 return hr;
1299 TRACE("Created swapchain %p.\n", object);
1300 *swapchain = (IWineD3DSwapChain *)object;
1302 return WINED3D_OK;
1305 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1306 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 TRACE("(%p)\n", This);
1310 return This->NumberOfSwapChains;
1313 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1315 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1317 if(iSwapChain < This->NumberOfSwapChains) {
1318 *pSwapChain = This->swapchains[iSwapChain];
1319 IWineD3DSwapChain_AddRef(*pSwapChain);
1320 TRACE("(%p) returning %p\n", This, *pSwapChain);
1321 return WINED3D_OK;
1322 } else {
1323 TRACE("Swapchain out of range\n");
1324 *pSwapChain = NULL;
1325 return WINED3DERR_INVALIDCALL;
1329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1330 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1331 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1334 IWineD3DVertexDeclarationImpl *object = NULL;
1335 HRESULT hr;
1337 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1338 iface, declaration, parent, elements, element_count);
1340 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1341 if(!object)
1343 ERR("Failed to allocate vertex declaration memory.\n");
1344 return E_OUTOFMEMORY;
1347 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1348 if (FAILED(hr))
1350 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1351 HeapFree(GetProcessHeap(), 0, object);
1352 return hr;
1355 TRACE("Created vertex declaration %p.\n", object);
1356 *declaration = (IWineD3DVertexDeclaration *)object;
1358 return WINED3D_OK;
1361 struct wined3d_fvf_convert_state
1363 const struct wined3d_gl_info *gl_info;
1364 WINED3DVERTEXELEMENT *elements;
1365 UINT offset;
1366 UINT idx;
1369 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1370 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1372 WINED3DVERTEXELEMENT *elements = state->elements;
1373 const struct wined3d_format_desc *format_desc;
1374 UINT offset = state->offset;
1375 UINT idx = state->idx;
1377 elements[idx].format = format;
1378 elements[idx].input_slot = 0;
1379 elements[idx].offset = offset;
1380 elements[idx].output_slot = 0;
1381 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1382 elements[idx].usage = usage;
1383 elements[idx].usage_idx = usage_idx;
1385 format_desc = getFormatDescEntry(format, state->gl_info);
1386 state->offset += format_desc->component_count * format_desc->component_size;
1387 ++state->idx;
1390 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1391 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1393 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1394 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1395 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1396 BOOL has_blend_idx = has_blend &&
1397 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1398 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1399 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1400 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1401 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1402 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1403 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1405 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1406 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1407 struct wined3d_fvf_convert_state state;
1408 unsigned int size;
1409 unsigned int idx;
1410 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1411 if (has_blend_idx) num_blends--;
1413 /* Compute declaration size */
1414 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1415 has_psize + has_diffuse + has_specular + num_textures;
1417 state.gl_info = gl_info;
1418 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1419 if (!state.elements) return ~0U;
1420 state.offset = 0;
1421 state.idx = 0;
1423 if (has_pos)
1425 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1426 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1427 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1428 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1429 else
1430 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1433 if (has_blend && (num_blends > 0))
1435 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1436 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 else
1439 switch (num_blends)
1441 case 1:
1442 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 case 2:
1445 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 break;
1447 case 3:
1448 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 break;
1450 case 4:
1451 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1452 break;
1453 default:
1454 ERR("Unexpected amount of blend values: %u\n", num_blends);
1459 if (has_blend_idx)
1461 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1462 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1463 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1464 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1465 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1466 else
1467 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1470 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1471 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1472 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1473 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1475 for (idx = 0; idx < num_textures; ++idx)
1477 switch ((texcoords >> (idx * 2)) & 0x03)
1479 case WINED3DFVF_TEXTUREFORMAT1:
1480 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1482 case WINED3DFVF_TEXTUREFORMAT2:
1483 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1484 break;
1485 case WINED3DFVF_TEXTUREFORMAT3:
1486 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1487 break;
1488 case WINED3DFVF_TEXTUREFORMAT4:
1489 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1490 break;
1494 *ppVertexElements = state.elements;
1495 return size;
1498 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1499 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1500 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1503 WINED3DVERTEXELEMENT *elements;
1504 unsigned int size;
1505 DWORD hr;
1507 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1509 size = ConvertFvfToDeclaration(This, fvf, &elements);
1510 if (size == ~0U) return E_OUTOFMEMORY;
1512 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1513 HeapFree(GetProcessHeap(), 0, elements);
1514 return hr;
1517 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1518 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1519 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1520 const struct wined3d_parent_ops *parent_ops)
1522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1523 IWineD3DVertexShaderImpl *object;
1524 HRESULT hr;
1526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1527 if (!object)
1529 ERR("Failed to allocate shader memory.\n");
1530 return E_OUTOFMEMORY;
1533 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1534 if (FAILED(hr))
1536 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1537 HeapFree(GetProcessHeap(), 0, object);
1538 return hr;
1541 TRACE("Created vertex shader %p.\n", object);
1542 *ppVertexShader = (IWineD3DVertexShader *)object;
1544 return WINED3D_OK;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1548 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1549 IWineD3DGeometryShader **shader, IUnknown *parent,
1550 const struct wined3d_parent_ops *parent_ops)
1552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1553 struct wined3d_geometryshader *object;
1554 HRESULT hr;
1556 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1557 if (!object)
1559 ERR("Failed to allocate shader memory.\n");
1560 return E_OUTOFMEMORY;
1563 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1564 if (FAILED(hr))
1566 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1567 HeapFree(GetProcessHeap(), 0, object);
1568 return hr;
1571 TRACE("Created geometry shader %p.\n", object);
1572 *shader = (IWineD3DGeometryShader *)object;
1574 return WINED3D_OK;
1577 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1578 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1579 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1580 const struct wined3d_parent_ops *parent_ops)
1582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1583 IWineD3DPixelShaderImpl *object;
1584 HRESULT hr;
1586 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1587 if (!object)
1589 ERR("Failed to allocate shader memory.\n");
1590 return E_OUTOFMEMORY;
1593 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1594 if (FAILED(hr))
1596 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1597 HeapFree(GetProcessHeap(), 0, object);
1598 return hr;
1601 TRACE("Created pixel shader %p.\n", object);
1602 *ppPixelShader = (IWineD3DPixelShader *)object;
1604 return WINED3D_OK;
1607 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1608 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1611 IWineD3DPaletteImpl *object;
1612 HRESULT hr;
1614 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1615 iface, Flags, PalEnt, Palette, Parent);
1617 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1618 if (!object)
1620 ERR("Failed to allocate palette memory.\n");
1621 return E_OUTOFMEMORY;
1624 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1625 if (FAILED(hr))
1627 WARN("Failed to initialize palette, hr %#x.\n", hr);
1628 HeapFree(GetProcessHeap(), 0, object);
1629 return hr;
1632 TRACE("Created palette %p.\n", object);
1633 *Palette = (IWineD3DPalette *)object;
1635 return WINED3D_OK;
1638 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1639 HBITMAP hbm;
1640 BITMAP bm;
1641 HRESULT hr;
1642 HDC dcb = NULL, dcs = NULL;
1643 WINEDDCOLORKEY colorkey;
1645 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1646 if(hbm)
1648 GetObjectA(hbm, sizeof(BITMAP), &bm);
1649 dcb = CreateCompatibleDC(NULL);
1650 if(!dcb) goto out;
1651 SelectObject(dcb, hbm);
1653 else
1655 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1656 * couldn't be loaded
1658 memset(&bm, 0, sizeof(bm));
1659 bm.bmWidth = 32;
1660 bm.bmHeight = 32;
1663 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1664 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1665 NULL, &wined3d_null_parent_ops);
1666 if(FAILED(hr)) {
1667 ERR("Wine logo requested, but failed to create surface\n");
1668 goto out;
1671 if(dcb) {
1672 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1673 if(FAILED(hr)) goto out;
1674 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1675 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1677 colorkey.dwColorSpaceLowValue = 0;
1678 colorkey.dwColorSpaceHighValue = 0;
1679 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1680 } else {
1681 /* Fill the surface with a white color to show that wined3d is there */
1682 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1685 out:
1686 if (dcb) DeleteDC(dcb);
1687 if (hbm) DeleteObject(hbm);
1690 /* Context activation is done by the caller. */
1691 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1693 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1694 unsigned int i;
1695 /* Under DirectX you can have texture stage operations even if no texture is
1696 bound, whereas opengl will only do texture operations when a valid texture is
1697 bound. We emulate this by creating dummy textures and binding them to each
1698 texture stage, but disable all stages by default. Hence if a stage is enabled
1699 then the default texture will kick in until replaced by a SetTexture call */
1700 ENTER_GL();
1702 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1704 /* The dummy texture does not have client storage backing */
1705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1709 for (i = 0; i < gl_info->limits.textures; ++i)
1711 GLubyte white = 255;
1713 /* Make appropriate texture active */
1714 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1715 checkGLcall("glActiveTextureARB");
1717 /* Generate an opengl texture name */
1718 glGenTextures(1, &This->dummyTextureName[i]);
1719 checkGLcall("glGenTextures");
1720 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1722 /* Generate a dummy 2d texture (not using 1d because they cause many
1723 * DRI drivers fall back to sw) */
1724 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1725 checkGLcall("glBindTexture");
1727 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1728 checkGLcall("glTexImage2D");
1731 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1733 /* Reenable because if supported it is enabled by default */
1734 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1735 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1738 LEAVE_GL();
1741 /* Context activation is done by the caller. */
1742 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1744 ENTER_GL();
1745 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1746 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1747 LEAVE_GL();
1749 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1752 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1754 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1756 if (!wined3d_register_window(window, device))
1758 ERR("Failed to register window %p.\n", window);
1759 return E_FAIL;
1762 device->focus_window = window;
1763 SetForegroundWindow(window);
1765 return WINED3D_OK;
1768 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1770 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1772 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1773 device->focus_window = NULL;
1776 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1777 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1780 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1781 IWineD3DSwapChainImpl *swapchain = NULL;
1782 struct wined3d_context *context;
1783 HRESULT hr;
1784 DWORD state;
1785 unsigned int i;
1787 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1789 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1790 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1792 TRACE("(%p) : Creating stateblock\n", This);
1793 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1794 if (FAILED(hr))
1796 WARN("Failed to create stateblock\n");
1797 goto err_out;
1799 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1800 This->updateStateBlock = This->stateBlock;
1801 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1803 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1804 sizeof(*This->render_targets) * gl_info->limits.buffers);
1806 This->NumberOfPalettes = 1;
1807 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1808 if (!This->palettes || !This->render_targets)
1810 ERR("Out of memory!\n");
1811 hr = E_OUTOFMEMORY;
1812 goto err_out;
1814 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1815 if(!This->palettes[0]) {
1816 ERR("Out of memory!\n");
1817 hr = E_OUTOFMEMORY;
1818 goto err_out;
1820 for (i = 0; i < 256; ++i) {
1821 This->palettes[0][i].peRed = 0xFF;
1822 This->palettes[0][i].peGreen = 0xFF;
1823 This->palettes[0][i].peBlue = 0xFF;
1824 This->palettes[0][i].peFlags = 0xFF;
1826 This->currentPalette = 0;
1828 /* Initialize the texture unit mapping to a 1:1 mapping */
1829 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1831 if (state < gl_info->limits.fragment_samplers)
1833 This->texUnitMap[state] = state;
1834 This->rev_tex_unit_map[state] = state;
1835 } else {
1836 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1837 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1841 /* Setup the implicit swapchain. This also initializes a context. */
1842 TRACE("Creating implicit swapchain\n");
1843 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1844 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1845 if (FAILED(hr))
1847 WARN("Failed to create implicit swapchain\n");
1848 goto err_out;
1851 This->NumberOfSwapChains = 1;
1852 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1853 if(!This->swapchains) {
1854 ERR("Out of memory!\n");
1855 goto err_out;
1857 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1859 if (swapchain->back_buffers && swapchain->back_buffers[0])
1861 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1862 This->render_targets[0] = swapchain->back_buffers[0];
1864 else
1866 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1867 This->render_targets[0] = swapchain->front_buffer;
1869 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1871 /* Depth Stencil support */
1872 This->depth_stencil = This->auto_depth_stencil;
1873 if (This->depth_stencil)
1874 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1876 hr = This->shader_backend->shader_alloc_private(iface);
1877 if(FAILED(hr)) {
1878 TRACE("Shader private data couldn't be allocated\n");
1879 goto err_out;
1881 hr = This->frag_pipe->alloc_private(iface);
1882 if(FAILED(hr)) {
1883 TRACE("Fragment pipeline private data couldn't be allocated\n");
1884 goto err_out;
1886 hr = This->blitter->alloc_private(iface);
1887 if(FAILED(hr)) {
1888 TRACE("Blitter private data couldn't be allocated\n");
1889 goto err_out;
1892 /* Set up some starting GL setup */
1894 /* Setup all the devices defaults */
1895 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1897 context = context_acquire(This, swapchain->front_buffer);
1899 create_dummy_textures(This);
1901 ENTER_GL();
1903 /* Initialize the current view state */
1904 This->view_ident = 1;
1905 This->contexts[0]->last_was_rhw = 0;
1906 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1907 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1909 switch(wined3d_settings.offscreen_rendering_mode) {
1910 case ORM_FBO:
1911 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1912 break;
1914 case ORM_BACKBUFFER:
1916 if (context_get_current()->aux_buffers > 0)
1918 TRACE("Using auxilliary buffer for offscreen rendering\n");
1919 This->offscreenBuffer = GL_AUX0;
1920 } else {
1921 TRACE("Using back buffer for offscreen rendering\n");
1922 This->offscreenBuffer = GL_BACK;
1927 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1928 LEAVE_GL();
1930 context_release(context);
1932 /* Clear the screen */
1933 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1934 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1935 0x00, 1.0f, 0);
1937 This->d3d_initialized = TRUE;
1939 if(wined3d_settings.logo) {
1940 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1942 This->highest_dirty_ps_const = 0;
1943 This->highest_dirty_vs_const = 0;
1944 return WINED3D_OK;
1946 err_out:
1947 HeapFree(GetProcessHeap(), 0, This->render_targets);
1948 HeapFree(GetProcessHeap(), 0, This->swapchains);
1949 This->NumberOfSwapChains = 0;
1950 if(This->palettes) {
1951 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1952 HeapFree(GetProcessHeap(), 0, This->palettes);
1954 This->NumberOfPalettes = 0;
1955 if(swapchain) {
1956 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1958 if(This->stateBlock) {
1959 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1960 This->stateBlock = NULL;
1962 if (This->blit_priv) {
1963 This->blitter->free_private(iface);
1965 if (This->fragment_priv) {
1966 This->frag_pipe->free_private(iface);
1968 if (This->shader_priv) {
1969 This->shader_backend->shader_free_private(iface);
1971 return hr;
1974 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1975 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1978 IWineD3DSwapChainImpl *swapchain = NULL;
1979 HRESULT hr;
1981 /* Setup the implicit swapchain */
1982 TRACE("Creating implicit swapchain\n");
1983 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1984 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1985 if (FAILED(hr))
1987 WARN("Failed to create implicit swapchain\n");
1988 goto err_out;
1991 This->NumberOfSwapChains = 1;
1992 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1993 if(!This->swapchains) {
1994 ERR("Out of memory!\n");
1995 goto err_out;
1997 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1998 return WINED3D_OK;
2000 err_out:
2001 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2002 return hr;
2005 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2007 IWineD3DResource_UnLoad(resource);
2008 IWineD3DResource_Release(resource);
2009 return WINED3D_OK;
2012 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2013 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2016 const struct wined3d_gl_info *gl_info;
2017 struct wined3d_context *context;
2018 int sampler;
2019 UINT i;
2020 TRACE("(%p)\n", This);
2022 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2025 * it was created. Thus make sure a context is active for the glDelete* calls
2027 context = context_acquire(This, NULL);
2028 gl_info = context->gl_info;
2030 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2032 /* Unload resources */
2033 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2035 TRACE("Deleting high order patches\n");
2036 for(i = 0; i < PATCHMAP_SIZE; i++) {
2037 struct list *e1, *e2;
2038 struct WineD3DRectPatch *patch;
2039 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2040 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2041 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2045 /* Delete the mouse cursor texture */
2046 if(This->cursorTexture) {
2047 ENTER_GL();
2048 glDeleteTextures(1, &This->cursorTexture);
2049 LEAVE_GL();
2050 This->cursorTexture = 0;
2053 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2054 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2056 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2057 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2060 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2061 * private data, it might contain opengl pointers
2063 if(This->depth_blt_texture) {
2064 ENTER_GL();
2065 glDeleteTextures(1, &This->depth_blt_texture);
2066 LEAVE_GL();
2067 This->depth_blt_texture = 0;
2069 if (This->depth_blt_rb) {
2070 ENTER_GL();
2071 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2072 LEAVE_GL();
2073 This->depth_blt_rb = 0;
2074 This->depth_blt_rb_w = 0;
2075 This->depth_blt_rb_h = 0;
2078 /* Release the update stateblock */
2079 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2080 if(This->updateStateBlock != This->stateBlock)
2081 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2083 This->updateStateBlock = NULL;
2085 { /* because were not doing proper internal refcounts releasing the primary state block
2086 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2087 to set this->stateBlock = NULL; first */
2088 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2089 This->stateBlock = NULL;
2091 /* Release the stateblock */
2092 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2093 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2097 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2098 This->blitter->free_private(iface);
2099 This->frag_pipe->free_private(iface);
2100 This->shader_backend->shader_free_private(iface);
2102 /* Release the buffers (with sanity checks)*/
2103 if (This->onscreen_depth_stencil)
2105 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2106 This->onscreen_depth_stencil = NULL;
2109 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2110 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2112 if (This->auto_depth_stencil != This->depth_stencil)
2113 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2115 This->depth_stencil = NULL;
2117 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2118 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2120 TRACE("Setting rendertarget to NULL\n");
2121 This->render_targets[0] = NULL;
2123 if (This->auto_depth_stencil)
2125 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2127 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2129 This->auto_depth_stencil = NULL;
2132 context_release(context);
2134 for(i=0; i < This->NumberOfSwapChains; i++) {
2135 TRACE("Releasing the implicit swapchain %d\n", i);
2136 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2137 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2141 HeapFree(GetProcessHeap(), 0, This->swapchains);
2142 This->swapchains = NULL;
2143 This->NumberOfSwapChains = 0;
2145 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2146 HeapFree(GetProcessHeap(), 0, This->palettes);
2147 This->palettes = NULL;
2148 This->NumberOfPalettes = 0;
2150 HeapFree(GetProcessHeap(), 0, This->render_targets);
2151 This->render_targets = NULL;
2153 This->d3d_initialized = FALSE;
2155 return WINED3D_OK;
2158 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2160 unsigned int i;
2162 for(i=0; i < This->NumberOfSwapChains; i++) {
2163 TRACE("Releasing the implicit swapchain %d\n", i);
2164 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2165 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2169 HeapFree(GetProcessHeap(), 0, This->swapchains);
2170 This->swapchains = NULL;
2171 This->NumberOfSwapChains = 0;
2172 return WINED3D_OK;
2175 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2176 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2177 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2179 * There is no way to deactivate thread safety once it is enabled.
2181 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2184 /*For now just store the flag(needed in case of ddraw) */
2185 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2188 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2189 const WINED3DDISPLAYMODE* pMode) {
2190 DEVMODEW devmode;
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2192 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2193 LONG ret;
2194 RECT clip_rc;
2196 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2198 /* Resize the screen even without a window:
2199 * The app could have unset it with SetCooperativeLevel, but not called
2200 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2201 * but we don't have any hwnd
2204 memset(&devmode, 0, sizeof(devmode));
2205 devmode.dmSize = sizeof(devmode);
2206 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2207 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2208 devmode.dmPelsWidth = pMode->Width;
2209 devmode.dmPelsHeight = pMode->Height;
2211 devmode.dmDisplayFrequency = pMode->RefreshRate;
2212 if (pMode->RefreshRate != 0) {
2213 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2216 /* Only change the mode if necessary */
2217 if( (This->ddraw_width == pMode->Width) &&
2218 (This->ddraw_height == pMode->Height) &&
2219 (This->ddraw_format == pMode->Format) &&
2220 (pMode->RefreshRate == 0) ) {
2221 return WINED3D_OK;
2224 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2225 if (ret != DISP_CHANGE_SUCCESSFUL) {
2226 if(devmode.dmDisplayFrequency != 0) {
2227 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2228 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2229 devmode.dmDisplayFrequency = 0;
2230 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2232 if(ret != DISP_CHANGE_SUCCESSFUL) {
2233 return WINED3DERR_NOTAVAILABLE;
2237 /* Store the new values */
2238 This->ddraw_width = pMode->Width;
2239 This->ddraw_height = pMode->Height;
2240 This->ddraw_format = pMode->Format;
2242 /* And finally clip mouse to our screen */
2243 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2244 ClipCursor(&clip_rc);
2246 return WINED3D_OK;
2249 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 *ppD3D = This->wined3d;
2252 TRACE("Returning %p.\n", *ppD3D);
2253 IWineD3D_AddRef(*ppD3D);
2254 return WINED3D_OK;
2257 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2261 (This->adapter->TextureRam/(1024*1024)),
2262 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2263 /* return simulated texture memory left */
2264 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2267 /*****
2268 * Get / Set Stream Source
2269 *****/
2270 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2271 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 IWineD3DBuffer *oldSrc;
2276 if (StreamNumber >= MAX_STREAMS) {
2277 WARN("Stream out of range %d\n", StreamNumber);
2278 return WINED3DERR_INVALIDCALL;
2279 } else if(OffsetInBytes & 0x3) {
2280 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2281 return WINED3DERR_INVALIDCALL;
2284 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2285 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2287 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2289 if(oldSrc == pStreamData &&
2290 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2291 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2292 TRACE("Application is setting the old values over, nothing to do\n");
2293 return WINED3D_OK;
2296 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2297 if (pStreamData) {
2298 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2299 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2302 /* Handle recording of state blocks */
2303 if (This->isRecordingState) {
2304 TRACE("Recording... not performing anything\n");
2305 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2306 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2307 return WINED3D_OK;
2310 if (pStreamData != NULL) {
2311 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2312 IWineD3DBuffer_AddRef(pStreamData);
2314 if (oldSrc != NULL) {
2315 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2316 IWineD3DBuffer_Release(oldSrc);
2319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2321 return WINED3D_OK;
2324 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2325 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2330 This->stateBlock->streamSource[StreamNumber],
2331 This->stateBlock->streamOffset[StreamNumber],
2332 This->stateBlock->streamStride[StreamNumber]);
2334 if (StreamNumber >= MAX_STREAMS) {
2335 WARN("Stream out of range %d\n", StreamNumber);
2336 return WINED3DERR_INVALIDCALL;
2338 *pStream = This->stateBlock->streamSource[StreamNumber];
2339 *pStride = This->stateBlock->streamStride[StreamNumber];
2340 if (pOffset) {
2341 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2344 if (*pStream != NULL) {
2345 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2347 return WINED3D_OK;
2350 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2353 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2355 /* Verify input at least in d3d9 this is invalid*/
2356 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2357 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2358 return WINED3DERR_INVALIDCALL;
2360 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2361 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2362 return WINED3DERR_INVALIDCALL;
2364 if( Divider == 0 ){
2365 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2369 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2370 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2372 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2373 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2375 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2376 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2380 return WINED3D_OK;
2383 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2386 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2387 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2389 TRACE("(%p) : returning %d\n", This, *Divider);
2391 return WINED3D_OK;
2394 /*****
2395 * Get / Set & Multiply Transform
2396 *****/
2397 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2400 /* Most of this routine, comments included copied from ddraw tree initially: */
2401 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2403 /* Handle recording of state blocks */
2404 if (This->isRecordingState) {
2405 TRACE("Recording... not performing anything\n");
2406 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2407 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2408 return WINED3D_OK;
2412 * If the new matrix is the same as the current one,
2413 * we cut off any further processing. this seems to be a reasonable
2414 * optimization because as was noticed, some apps (warcraft3 for example)
2415 * tend towards setting the same matrix repeatedly for some reason.
2417 * From here on we assume that the new matrix is different, wherever it matters.
2419 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2420 TRACE("The app is setting the same matrix over again\n");
2421 return WINED3D_OK;
2422 } else {
2423 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2427 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2428 where ViewMat = Camera space, WorldMat = world space.
2430 In OpenGL, camera and world space is combined into GL_MODELVIEW
2431 matrix. The Projection matrix stay projection matrix.
2434 /* Capture the times we can just ignore the change for now */
2435 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2436 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2437 /* Handled by the state manager */
2440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2441 return WINED3D_OK;
2444 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2446 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2447 *pMatrix = This->stateBlock->transforms[State];
2448 return WINED3D_OK;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2452 const WINED3DMATRIX *mat = NULL;
2453 WINED3DMATRIX temp;
2455 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2456 * below means it will be recorded in a state block change, but it
2457 * works regardless where it is recorded.
2458 * If this is found to be wrong, change to StateBlock.
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2463 if (State <= HIGHEST_TRANSFORMSTATE)
2465 mat = &This->updateStateBlock->transforms[State];
2466 } else {
2467 FIXME("Unhandled transform state!!\n");
2470 multiply_matrix(&temp, mat, pMatrix);
2472 /* Apply change via set transform - will reapply to eg. lights this way */
2473 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2476 /*****
2477 * Get / Set Light
2478 *****/
2479 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2480 you can reference any indexes you want as long as that number max are enabled at any
2481 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2482 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2483 but when recording, just build a chain pretty much of commands to be replayed. */
2485 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2486 float rho;
2487 struct wined3d_light_info *object = NULL;
2488 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2489 struct list *e;
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2494 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2495 * the gl driver.
2497 if(!pLight) {
2498 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2499 return WINED3DERR_INVALIDCALL;
2502 switch(pLight->Type) {
2503 case WINED3DLIGHT_POINT:
2504 case WINED3DLIGHT_SPOT:
2505 case WINED3DLIGHT_PARALLELPOINT:
2506 case WINED3DLIGHT_GLSPOT:
2507 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2508 * most wanted
2510 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2512 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2513 return WINED3DERR_INVALIDCALL;
2515 break;
2517 case WINED3DLIGHT_DIRECTIONAL:
2518 /* Ignores attenuation */
2519 break;
2521 default:
2522 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2523 return WINED3DERR_INVALIDCALL;
2526 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2528 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2529 if(object->OriginalIndex == Index) break;
2530 object = NULL;
2533 if(!object) {
2534 TRACE("Adding new light\n");
2535 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2536 if(!object) {
2537 ERR("Out of memory error when allocating a light\n");
2538 return E_OUTOFMEMORY;
2540 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2541 object->glIndex = -1;
2542 object->OriginalIndex = Index;
2545 /* Initialize the object */
2546 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,
2547 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2548 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2549 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2550 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2551 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2552 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2554 /* Save away the information */
2555 object->OriginalParms = *pLight;
2557 switch (pLight->Type) {
2558 case WINED3DLIGHT_POINT:
2559 /* Position */
2560 object->lightPosn[0] = pLight->Position.x;
2561 object->lightPosn[1] = pLight->Position.y;
2562 object->lightPosn[2] = pLight->Position.z;
2563 object->lightPosn[3] = 1.0f;
2564 object->cutoff = 180.0f;
2565 /* FIXME: Range */
2566 break;
2568 case WINED3DLIGHT_DIRECTIONAL:
2569 /* Direction */
2570 object->lightPosn[0] = -pLight->Direction.x;
2571 object->lightPosn[1] = -pLight->Direction.y;
2572 object->lightPosn[2] = -pLight->Direction.z;
2573 object->lightPosn[3] = 0.0f;
2574 object->exponent = 0.0f;
2575 object->cutoff = 180.0f;
2576 break;
2578 case WINED3DLIGHT_SPOT:
2579 /* Position */
2580 object->lightPosn[0] = pLight->Position.x;
2581 object->lightPosn[1] = pLight->Position.y;
2582 object->lightPosn[2] = pLight->Position.z;
2583 object->lightPosn[3] = 1.0f;
2585 /* Direction */
2586 object->lightDirn[0] = pLight->Direction.x;
2587 object->lightDirn[1] = pLight->Direction.y;
2588 object->lightDirn[2] = pLight->Direction.z;
2589 object->lightDirn[3] = 1.0f;
2592 * opengl-ish and d3d-ish spot lights use too different models for the
2593 * light "intensity" as a function of the angle towards the main light direction,
2594 * so we only can approximate very roughly.
2595 * however spot lights are rather rarely used in games (if ever used at all).
2596 * furthermore if still used, probably nobody pays attention to such details.
2598 if (pLight->Falloff == 0) {
2599 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2600 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2601 * will always be 1.0 for both of them, and we don't have to care for the
2602 * rest of the rather complex calculation
2604 object->exponent = 0.0f;
2605 } else {
2606 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2607 if (rho < 0.0001f) rho = 0.0001f;
2608 object->exponent = -0.3f/logf(cosf(rho/2));
2610 if (object->exponent > 128.0f)
2612 object->exponent = 128.0f;
2614 object->cutoff = (float) (pLight->Phi*90/M_PI);
2616 /* FIXME: Range */
2617 break;
2619 default:
2620 FIXME("Unrecognized light type %d\n", pLight->Type);
2623 /* Update the live definitions if the light is currently assigned a glIndex */
2624 if (object->glIndex != -1 && !This->isRecordingState) {
2625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2627 return WINED3D_OK;
2630 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2632 struct wined3d_light_info *lightInfo = NULL;
2633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2634 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2635 struct list *e;
2636 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2638 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2640 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2641 if(lightInfo->OriginalIndex == Index) break;
2642 lightInfo = NULL;
2645 if (lightInfo == NULL) {
2646 TRACE("Light information requested but light not defined\n");
2647 return WINED3DERR_INVALIDCALL;
2650 *pLight = lightInfo->OriginalParms;
2651 return WINED3D_OK;
2654 /*****
2655 * Get / Set Light Enable
2656 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2657 *****/
2658 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2660 struct wined3d_light_info *lightInfo = NULL;
2661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2663 struct list *e;
2664 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2666 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2668 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2669 if(lightInfo->OriginalIndex == Index) break;
2670 lightInfo = NULL;
2672 TRACE("Found light: %p\n", lightInfo);
2674 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2675 if (lightInfo == NULL) {
2677 TRACE("Light enabled requested but light not defined, so defining one!\n");
2678 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2680 /* Search for it again! Should be fairly quick as near head of list */
2681 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2683 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2684 if(lightInfo->OriginalIndex == Index) break;
2685 lightInfo = NULL;
2687 if (lightInfo == NULL) {
2688 FIXME("Adding default lights has failed dismally\n");
2689 return WINED3DERR_INVALIDCALL;
2693 if(!Enable) {
2694 if(lightInfo->glIndex != -1) {
2695 if(!This->isRecordingState) {
2696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2699 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2700 lightInfo->glIndex = -1;
2701 } else {
2702 TRACE("Light already disabled, nothing to do\n");
2704 lightInfo->enabled = FALSE;
2705 } else {
2706 lightInfo->enabled = TRUE;
2707 if (lightInfo->glIndex != -1) {
2708 /* nop */
2709 TRACE("Nothing to do as light was enabled\n");
2710 } else {
2711 int i;
2712 /* Find a free gl light */
2713 for(i = 0; i < This->maxConcurrentLights; i++) {
2714 if(This->updateStateBlock->activeLights[i] == NULL) {
2715 This->updateStateBlock->activeLights[i] = lightInfo;
2716 lightInfo->glIndex = i;
2717 break;
2720 if(lightInfo->glIndex == -1) {
2721 /* Our tests show that Windows returns D3D_OK in this situation, even with
2722 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2723 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2724 * as well for those lights.
2726 * TODO: Test how this affects rendering
2728 WARN("Too many concurrently active lights\n");
2729 return WINED3D_OK;
2732 /* i == lightInfo->glIndex */
2733 if(!This->isRecordingState) {
2734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2739 return WINED3D_OK;
2742 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2744 struct wined3d_light_info *lightInfo = NULL;
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2746 struct list *e;
2747 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2748 TRACE("(%p) : for idx(%d)\n", This, Index);
2750 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2752 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2753 if(lightInfo->OriginalIndex == Index) break;
2754 lightInfo = NULL;
2757 if (lightInfo == NULL) {
2758 TRACE("Light enabled state requested but light not defined\n");
2759 return WINED3DERR_INVALIDCALL;
2761 /* true is 128 according to SetLightEnable */
2762 *pEnable = lightInfo->enabled ? 128 : 0;
2763 return WINED3D_OK;
2766 /*****
2767 * Get / Set Clip Planes
2768 *****/
2769 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2771 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2773 /* Validate Index */
2774 if (Index >= This->adapter->gl_info.limits.clipplanes)
2776 TRACE("Application has requested clipplane this device doesn't support\n");
2777 return WINED3DERR_INVALIDCALL;
2780 This->updateStateBlock->changed.clipplane |= 1 << Index;
2782 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2783 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2784 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2785 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2786 TRACE("Application is setting old values over, nothing to do\n");
2787 return WINED3D_OK;
2790 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2791 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2792 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2793 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2795 /* Handle recording of state blocks */
2796 if (This->isRecordingState) {
2797 TRACE("Recording... not performing anything\n");
2798 return WINED3D_OK;
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2803 return WINED3D_OK;
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 TRACE("(%p) : for idx %d\n", This, Index);
2810 /* Validate Index */
2811 if (Index >= This->adapter->gl_info.limits.clipplanes)
2813 TRACE("Application has requested clipplane this device doesn't support\n");
2814 return WINED3DERR_INVALIDCALL;
2817 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2818 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2819 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2820 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2821 return WINED3D_OK;
2824 /*****
2825 * Get / Set Clip Plane Status
2826 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2827 *****/
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 FIXME("(%p) : stub\n", This);
2831 if (NULL == pClipStatus) {
2832 return WINED3DERR_INVALIDCALL;
2834 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2835 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2836 return WINED3D_OK;
2839 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2841 FIXME("(%p) : stub\n", This);
2842 if (NULL == pClipStatus) {
2843 return WINED3DERR_INVALIDCALL;
2845 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2846 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2847 return WINED3D_OK;
2850 /*****
2851 * Get / Set Material
2852 *****/
2853 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2856 This->updateStateBlock->changed.material = TRUE;
2857 This->updateStateBlock->material = *pMaterial;
2859 /* Handle recording of state blocks */
2860 if (This->isRecordingState) {
2861 TRACE("Recording... not performing anything\n");
2862 return WINED3D_OK;
2865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2866 return WINED3D_OK;
2869 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 *pMaterial = This->updateStateBlock->material;
2872 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2873 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2874 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2875 pMaterial->Ambient.b, pMaterial->Ambient.a);
2876 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2877 pMaterial->Specular.b, pMaterial->Specular.a);
2878 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2879 pMaterial->Emissive.b, pMaterial->Emissive.a);
2880 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2882 return WINED3D_OK;
2885 /*****
2886 * Get / Set Indices
2887 *****/
2888 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2889 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 IWineD3DBuffer *oldIdxs;
2894 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2895 oldIdxs = This->updateStateBlock->pIndexData;
2897 This->updateStateBlock->changed.indices = TRUE;
2898 This->updateStateBlock->pIndexData = pIndexData;
2899 This->updateStateBlock->IndexFmt = fmt;
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2904 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2905 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2906 return WINED3D_OK;
2909 if(oldIdxs != pIndexData) {
2910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2911 if(pIndexData) {
2912 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2913 IWineD3DBuffer_AddRef(pIndexData);
2915 if(oldIdxs) {
2916 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2917 IWineD3DBuffer_Release(oldIdxs);
2921 return WINED3D_OK;
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 *ppIndexData = This->stateBlock->pIndexData;
2930 /* up ref count on ppindexdata */
2931 if (*ppIndexData) {
2932 IWineD3DBuffer_AddRef(*ppIndexData);
2933 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2934 }else{
2935 TRACE("(%p) No index data set\n", This);
2937 TRACE("Returning %p\n", *ppIndexData);
2939 return WINED3D_OK;
2942 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2943 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 TRACE("(%p)->(%d)\n", This, BaseIndex);
2947 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2948 TRACE("Application is setting the old value over, nothing to do\n");
2949 return WINED3D_OK;
2952 This->updateStateBlock->baseVertexIndex = BaseIndex;
2954 if (This->isRecordingState) {
2955 TRACE("Recording... not performing anything\n");
2956 return WINED3D_OK;
2958 /* The base vertex index affects the stream sources */
2959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2960 return WINED3D_OK;
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2965 TRACE("(%p) : base_index %p\n", This, base_index);
2967 *base_index = This->stateBlock->baseVertexIndex;
2969 TRACE("Returning %u\n", *base_index);
2971 return WINED3D_OK;
2974 /*****
2975 * Get / Set Viewports
2976 *****/
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 TRACE("(%p)\n", This);
2981 This->updateStateBlock->changed.viewport = TRUE;
2982 This->updateStateBlock->viewport = *pViewport;
2984 /* Handle recording of state blocks */
2985 if (This->isRecordingState) {
2986 TRACE("Recording... not performing anything\n");
2987 return WINED3D_OK;
2990 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2991 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2994 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 TRACE("(%p)\n", This);
3001 *pViewport = This->stateBlock->viewport;
3002 return WINED3D_OK;
3005 /*****
3006 * Get / Set Render States
3007 * TODO: Verify against dx9 definitions
3008 *****/
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 DWORD oldValue = This->stateBlock->renderState[State];
3014 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3016 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3017 This->updateStateBlock->renderState[State] = Value;
3019 /* Handle recording of state blocks */
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3025 /* Compared here and not before the assignment to allow proper stateblock recording */
3026 if(Value == oldValue) {
3027 TRACE("Application is setting the old value over, nothing to do\n");
3028 } else {
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3040 *pValue = This->stateBlock->renderState[State];
3041 return WINED3D_OK;
3044 /*****
3045 * Get / Set Sampler States
3046 * TODO: Verify against dx9 definitions
3047 *****/
3049 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 DWORD oldValue;
3053 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3054 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3056 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3057 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3060 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3061 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3062 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3065 * SetSampler is designed to allow for more than the standard up to 8 textures
3066 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3067 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3069 * http://developer.nvidia.com/object/General_FAQ.html#t6
3071 * There are two new settings for GForce
3072 * the sampler one:
3073 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3074 * and the texture one:
3075 * GL_MAX_TEXTURE_COORDS_ARB.
3076 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3077 ******************/
3079 oldValue = This->stateBlock->samplerState[Sampler][Type];
3080 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3081 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3083 /* Handle recording of state blocks */
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3086 return WINED3D_OK;
3089 if(oldValue == Value) {
3090 TRACE("Application is setting the old value over, nothing to do\n");
3091 return WINED3D_OK;
3094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3103 This, Sampler, debug_d3dsamplerstate(Type), Type);
3105 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3106 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3109 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3110 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3111 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3113 *Value = This->stateBlock->samplerState[Sampler][Type];
3114 TRACE("(%p) : Returning %#x\n", This, *Value);
3116 return WINED3D_OK;
3119 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3122 This->updateStateBlock->changed.scissorRect = TRUE;
3123 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3124 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3125 return WINED3D_OK;
3127 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3129 if(This->isRecordingState) {
3130 TRACE("Recording... not performing anything\n");
3131 return WINED3D_OK;
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3136 return WINED3D_OK;
3139 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 *pRect = This->updateStateBlock->scissorRect;
3143 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3144 return WINED3D_OK;
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3149 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3151 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3153 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3154 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3156 This->updateStateBlock->vertexDecl = pDecl;
3157 This->updateStateBlock->changed.vertexDecl = TRUE;
3159 if (This->isRecordingState) {
3160 TRACE("Recording... not performing anything\n");
3161 return WINED3D_OK;
3162 } else if(pDecl == oldDecl) {
3163 /* Checked after the assignment to allow proper stateblock recording */
3164 TRACE("Application is setting the old declaration over, nothing to do\n");
3165 return WINED3D_OK;
3168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3169 return WINED3D_OK;
3172 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3175 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3177 *ppDecl = This->stateBlock->vertexDecl;
3178 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3179 return WINED3D_OK;
3182 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3186 This->updateStateBlock->vertexShader = pShader;
3187 This->updateStateBlock->changed.vertexShader = TRUE;
3189 if (This->isRecordingState) {
3190 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3191 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3192 TRACE("Recording... not performing anything\n");
3193 return WINED3D_OK;
3194 } else if(oldShader == pShader) {
3195 /* Checked here to allow proper stateblock recording */
3196 TRACE("App is setting the old shader over, nothing to do\n");
3197 return WINED3D_OK;
3200 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3201 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3202 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3206 return WINED3D_OK;
3209 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 if (NULL == ppShader) {
3213 return WINED3DERR_INVALIDCALL;
3215 *ppShader = This->stateBlock->vertexShader;
3216 if( NULL != *ppShader)
3217 IWineD3DVertexShader_AddRef(*ppShader);
3219 TRACE("(%p) : returning %p\n", This, *ppShader);
3220 return WINED3D_OK;
3223 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3224 IWineD3DDevice *iface,
3225 UINT start,
3226 CONST BOOL *srcData,
3227 UINT count) {
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3232 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3233 iface, srcData, start, count);
3235 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3237 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3238 for (i = 0; i < cnt; i++)
3239 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3241 for (i = start; i < cnt + start; ++i) {
3242 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3245 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3251 IWineD3DDevice *iface,
3252 UINT start,
3253 BOOL *dstData,
3254 UINT count) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 int cnt = min(count, MAX_CONST_B - start);
3259 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3260 iface, dstData, start, count);
3262 if (dstData == NULL || cnt < 0)
3263 return WINED3DERR_INVALIDCALL;
3265 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3266 return WINED3D_OK;
3269 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3270 IWineD3DDevice *iface,
3271 UINT start,
3272 CONST int *srcData,
3273 UINT count) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3278 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3279 iface, srcData, start, count);
3281 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3283 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3284 for (i = 0; i < cnt; i++)
3285 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3286 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3288 for (i = start; i < cnt + start; ++i) {
3289 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3292 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3298 IWineD3DDevice *iface,
3299 UINT start,
3300 int *dstData,
3301 UINT count) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 int cnt = min(count, MAX_CONST_I - start);
3306 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3307 iface, dstData, start, count);
3309 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3310 return WINED3DERR_INVALIDCALL;
3312 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3313 return WINED3D_OK;
3316 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3317 IWineD3DDevice *iface,
3318 UINT start,
3319 CONST float *srcData,
3320 UINT count) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 UINT i;
3325 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3326 iface, srcData, start, count);
3328 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3329 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3330 return WINED3DERR_INVALIDCALL;
3332 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3333 if(TRACE_ON(d3d)) {
3334 for (i = 0; i < count; i++)
3335 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3336 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3339 if (!This->isRecordingState)
3341 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3345 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3346 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3348 return WINED3D_OK;
3351 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3352 IWineD3DDevice *iface,
3353 UINT start,
3354 float *dstData,
3355 UINT count) {
3357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 int cnt = min(count, This->d3d_vshader_constantF - start);
3360 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3361 iface, dstData, start, count);
3363 if (dstData == NULL || cnt < 0)
3364 return WINED3DERR_INVALIDCALL;
3366 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3367 return WINED3D_OK;
3370 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3371 DWORD i;
3372 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3378 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3380 DWORD i = This->rev_tex_unit_map[unit];
3381 DWORD j = This->texUnitMap[stage];
3383 This->texUnitMap[stage] = unit;
3384 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3386 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3389 This->rev_tex_unit_map[unit] = stage;
3390 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3392 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3396 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3397 int i;
3399 This->fixed_function_usage_map = 0;
3400 for (i = 0; i < MAX_TEXTURES; ++i) {
3401 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3402 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3403 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3404 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3405 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3406 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3407 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3408 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3410 if (color_op == WINED3DTOP_DISABLE) {
3411 /* Not used, and disable higher stages */
3412 break;
3415 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3416 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3417 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3418 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3419 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3420 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3421 This->fixed_function_usage_map |= (1 << i);
3424 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3425 This->fixed_function_usage_map |= (1 << (i + 1));
3430 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3432 unsigned int i, tex;
3433 WORD ffu_map;
3435 device_update_fixed_function_usage_map(This);
3436 ffu_map = This->fixed_function_usage_map;
3438 if (This->max_ffp_textures == gl_info->limits.texture_stages
3439 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3441 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3443 if (!(ffu_map & 1)) continue;
3445 if (This->texUnitMap[i] != i) {
3446 device_map_stage(This, i, i);
3447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3448 markTextureStagesDirty(This, i);
3451 return;
3454 /* Now work out the mapping */
3455 tex = 0;
3456 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3458 if (!(ffu_map & 1)) continue;
3460 if (This->texUnitMap[i] != tex) {
3461 device_map_stage(This, i, tex);
3462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3463 markTextureStagesDirty(This, i);
3466 ++tex;
3470 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3472 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3473 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3474 unsigned int i;
3476 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3477 if (sampler_type[i] && This->texUnitMap[i] != i)
3479 device_map_stage(This, i, i);
3480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3481 if (i < gl_info->limits.texture_stages)
3483 markTextureStagesDirty(This, i);
3489 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3490 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3492 DWORD current_mapping = This->rev_tex_unit_map[unit];
3494 /* Not currently used */
3495 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3497 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3498 /* Used by a fragment sampler */
3500 if (!pshader_sampler_tokens) {
3501 /* No pixel shader, check fixed function */
3502 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3505 /* Pixel shader, check the shader's sampler map */
3506 return !pshader_sampler_tokens[current_mapping];
3509 /* Used by a vertex sampler */
3510 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3513 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3515 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3516 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3517 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3518 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3519 int i;
3521 if (ps) {
3522 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3524 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3525 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3526 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3529 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3530 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3531 if (vshader_sampler_type[i])
3533 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3535 /* Already mapped somewhere */
3536 continue;
3539 while (start >= 0) {
3540 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3542 device_map_stage(This, vsampler_idx, start);
3543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3545 --start;
3546 break;
3549 --start;
3555 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3557 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3558 BOOL vs = use_vs(This->stateBlock);
3559 BOOL ps = use_ps(This->stateBlock);
3561 * Rules are:
3562 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3563 * that would be really messy and require shader recompilation
3564 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3565 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3567 if (ps) device_map_psamplers(This, gl_info);
3568 else device_map_fixed_function_samplers(This, gl_info);
3570 if (vs) device_map_vsamplers(This, ps, gl_info);
3573 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3575 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3576 This->updateStateBlock->pixelShader = pShader;
3577 This->updateStateBlock->changed.pixelShader = TRUE;
3579 /* Handle recording of state blocks */
3580 if (This->isRecordingState) {
3581 TRACE("Recording... not performing anything\n");
3584 if (This->isRecordingState) {
3585 TRACE("Recording... not performing anything\n");
3586 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3587 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3588 return WINED3D_OK;
3591 if(pShader == oldShader) {
3592 TRACE("App is setting the old pixel shader over, nothing to do\n");
3593 return WINED3D_OK;
3596 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3597 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3599 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3602 return WINED3D_OK;
3605 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 if (NULL == ppShader) {
3609 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3610 return WINED3DERR_INVALIDCALL;
3613 *ppShader = This->stateBlock->pixelShader;
3614 if (NULL != *ppShader) {
3615 IWineD3DPixelShader_AddRef(*ppShader);
3617 TRACE("(%p) : returning %p\n", This, *ppShader);
3618 return WINED3D_OK;
3621 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3622 IWineD3DDevice *iface,
3623 UINT start,
3624 CONST BOOL *srcData,
3625 UINT count) {
3627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3628 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3630 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3631 iface, srcData, start, count);
3633 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3635 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3636 for (i = 0; i < cnt; i++)
3637 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3639 for (i = start; i < cnt + start; ++i) {
3640 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3643 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3645 return WINED3D_OK;
3648 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3649 IWineD3DDevice *iface,
3650 UINT start,
3651 BOOL *dstData,
3652 UINT count) {
3654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655 int cnt = min(count, MAX_CONST_B - start);
3657 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3658 iface, dstData, start, count);
3660 if (dstData == NULL || cnt < 0)
3661 return WINED3DERR_INVALIDCALL;
3663 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3664 return WINED3D_OK;
3667 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3668 IWineD3DDevice *iface,
3669 UINT start,
3670 CONST int *srcData,
3671 UINT count) {
3673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3674 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3676 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3677 iface, srcData, start, count);
3679 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3681 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3682 for (i = 0; i < cnt; i++)
3683 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3684 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3686 for (i = start; i < cnt + start; ++i) {
3687 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3690 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3692 return WINED3D_OK;
3695 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3696 IWineD3DDevice *iface,
3697 UINT start,
3698 int *dstData,
3699 UINT count) {
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 int cnt = min(count, MAX_CONST_I - start);
3704 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3705 iface, dstData, start, count);
3707 if (dstData == NULL || cnt < 0)
3708 return WINED3DERR_INVALIDCALL;
3710 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3711 return WINED3D_OK;
3714 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3715 IWineD3DDevice *iface,
3716 UINT start,
3717 CONST float *srcData,
3718 UINT count) {
3720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3721 UINT i;
3723 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3724 iface, srcData, start, count);
3726 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3727 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3728 return WINED3DERR_INVALIDCALL;
3730 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3731 if(TRACE_ON(d3d)) {
3732 for (i = 0; i < count; i++)
3733 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3734 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3737 if (!This->isRecordingState)
3739 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3743 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3744 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3746 return WINED3D_OK;
3749 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3750 IWineD3DDevice *iface,
3751 UINT start,
3752 float *dstData,
3753 UINT count) {
3755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3756 int cnt = min(count, This->d3d_pshader_constantF - start);
3758 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3759 iface, dstData, start, count);
3761 if (dstData == NULL || cnt < 0)
3762 return WINED3DERR_INVALIDCALL;
3764 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3765 return WINED3D_OK;
3768 /* Context activation is done by the caller. */
3769 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3770 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3771 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3772 DWORD DestFVF)
3774 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3775 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3776 unsigned int i;
3777 WINED3DVIEWPORT vp;
3778 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3779 BOOL doClip;
3780 DWORD numTextures;
3782 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3784 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3787 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3789 ERR("Source has no position mask\n");
3790 return WINED3DERR_INVALIDCALL;
3793 /* We might access VBOs from this code, so hold the lock */
3794 ENTER_GL();
3796 if (!dest->resource.allocatedMemory)
3797 buffer_get_sysmem(dest, gl_info);
3799 /* Get a pointer into the destination vbo(create one if none exists) and
3800 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3802 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3804 dest->flags |= WINED3D_BUFFER_CREATEBO;
3805 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3808 if (dest->buffer_object)
3810 unsigned char extrabytes = 0;
3811 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3812 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3813 * this may write 4 extra bytes beyond the area that should be written
3815 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3816 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3817 if(!dest_conv_addr) {
3818 ERR("Out of memory\n");
3819 /* Continue without storing converted vertices */
3821 dest_conv = dest_conv_addr;
3824 /* Should I clip?
3825 * a) WINED3DRS_CLIPPING is enabled
3826 * b) WINED3DVOP_CLIP is passed
3828 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3829 static BOOL warned = FALSE;
3831 * The clipping code is not quite correct. Some things need
3832 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3833 * so disable clipping for now.
3834 * (The graphics in Half-Life are broken, and my processvertices
3835 * test crashes with IDirect3DDevice3)
3836 doClip = TRUE;
3838 doClip = FALSE;
3839 if(!warned) {
3840 warned = TRUE;
3841 FIXME("Clipping is broken and disabled for now\n");
3843 } else doClip = FALSE;
3844 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3846 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3847 WINED3DTS_VIEW,
3848 &view_mat);
3849 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3850 WINED3DTS_PROJECTION,
3851 &proj_mat);
3852 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3853 WINED3DTS_WORLDMATRIX(0),
3854 &world_mat);
3856 TRACE("View mat:\n");
3857 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);
3858 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);
3859 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);
3860 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);
3862 TRACE("Proj mat:\n");
3863 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);
3864 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);
3865 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);
3866 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);
3868 TRACE("World mat:\n");
3869 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);
3870 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);
3871 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);
3872 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);
3874 /* Get the viewport */
3875 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3876 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3877 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3879 multiply_matrix(&mat,&view_mat,&world_mat);
3880 multiply_matrix(&mat,&proj_mat,&mat);
3882 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3884 for (i = 0; i < dwCount; i+= 1) {
3885 unsigned int tex_index;
3887 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3888 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3889 /* The position first */
3890 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3891 const float *p = (const float *)(element->data + i * element->stride);
3892 float x, y, z, rhw;
3893 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3895 /* Multiplication with world, view and projection matrix */
3896 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);
3897 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);
3898 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);
3899 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);
3901 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3903 /* WARNING: The following things are taken from d3d7 and were not yet checked
3904 * against d3d8 or d3d9!
3907 /* Clipping conditions: From msdn
3909 * A vertex is clipped if it does not match the following requirements
3910 * -rhw < x <= rhw
3911 * -rhw < y <= rhw
3912 * 0 < z <= rhw
3913 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3915 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3916 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3920 if( !doClip ||
3921 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3922 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3923 ( rhw > eps ) ) ) {
3925 /* "Normal" viewport transformation (not clipped)
3926 * 1) The values are divided by rhw
3927 * 2) The y axis is negative, so multiply it with -1
3928 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3929 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3930 * 4) Multiply x with Width/2 and add Width/2
3931 * 5) The same for the height
3932 * 6) Add the viewpoint X and Y to the 2D coordinates and
3933 * The minimum Z value to z
3934 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3936 * Well, basically it's simply a linear transformation into viewport
3937 * coordinates
3940 x /= rhw;
3941 y /= rhw;
3942 z /= rhw;
3944 y *= -1;
3946 x *= vp.Width / 2;
3947 y *= vp.Height / 2;
3948 z *= vp.MaxZ - vp.MinZ;
3950 x += vp.Width / 2 + vp.X;
3951 y += vp.Height / 2 + vp.Y;
3952 z += vp.MinZ;
3954 rhw = 1 / rhw;
3955 } else {
3956 /* That vertex got clipped
3957 * Contrary to OpenGL it is not dropped completely, it just
3958 * undergoes a different calculation.
3960 TRACE("Vertex got clipped\n");
3961 x += rhw;
3962 y += rhw;
3964 x /= 2;
3965 y /= 2;
3967 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3968 * outside of the main vertex buffer memory. That needs some more
3969 * investigation...
3973 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3976 ( (float *) dest_ptr)[0] = x;
3977 ( (float *) dest_ptr)[1] = y;
3978 ( (float *) dest_ptr)[2] = z;
3979 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3981 dest_ptr += 3 * sizeof(float);
3983 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3984 dest_ptr += sizeof(float);
3987 if(dest_conv) {
3988 float w = 1 / rhw;
3989 ( (float *) dest_conv)[0] = x * w;
3990 ( (float *) dest_conv)[1] = y * w;
3991 ( (float *) dest_conv)[2] = z * w;
3992 ( (float *) dest_conv)[3] = w;
3994 dest_conv += 3 * sizeof(float);
3996 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3997 dest_conv += sizeof(float);
4001 if (DestFVF & WINED3DFVF_PSIZE) {
4002 dest_ptr += sizeof(DWORD);
4003 if(dest_conv) dest_conv += sizeof(DWORD);
4005 if (DestFVF & WINED3DFVF_NORMAL) {
4006 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4007 const float *normal = (const float *)(element->data + i * element->stride);
4008 /* AFAIK this should go into the lighting information */
4009 FIXME("Didn't expect the destination to have a normal\n");
4010 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4011 if(dest_conv) {
4012 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4016 if (DestFVF & WINED3DFVF_DIFFUSE) {
4017 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4018 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4019 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4021 static BOOL warned = FALSE;
4023 if(!warned) {
4024 ERR("No diffuse color in source, but destination has one\n");
4025 warned = TRUE;
4028 *( (DWORD *) dest_ptr) = 0xffffffff;
4029 dest_ptr += sizeof(DWORD);
4031 if(dest_conv) {
4032 *( (DWORD *) dest_conv) = 0xffffffff;
4033 dest_conv += sizeof(DWORD);
4036 else {
4037 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4038 if(dest_conv) {
4039 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4040 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4041 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4042 dest_conv += sizeof(DWORD);
4047 if (DestFVF & WINED3DFVF_SPECULAR)
4049 /* What's the color value in the feedback buffer? */
4050 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4051 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4052 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4054 static BOOL warned = FALSE;
4056 if(!warned) {
4057 ERR("No specular color in source, but destination has one\n");
4058 warned = TRUE;
4061 *( (DWORD *) dest_ptr) = 0xFF000000;
4062 dest_ptr += sizeof(DWORD);
4064 if(dest_conv) {
4065 *( (DWORD *) dest_conv) = 0xFF000000;
4066 dest_conv += sizeof(DWORD);
4069 else {
4070 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4071 if(dest_conv) {
4072 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4073 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4074 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4075 dest_conv += sizeof(DWORD);
4080 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4081 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4082 const float *tex_coord = (const float *)(element->data + i * element->stride);
4083 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4085 ERR("No source texture, but destination requests one\n");
4086 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4087 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4089 else {
4090 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4091 if(dest_conv) {
4092 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4098 if(dest_conv) {
4099 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4100 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4101 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4102 dwCount * get_flexible_vertex_size(DestFVF),
4103 dest_conv_addr));
4104 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4105 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4108 LEAVE_GL();
4110 return WINED3D_OK;
4112 #undef copy_and_next
4114 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4115 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4116 DWORD DestFVF)
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 struct wined3d_stream_info stream_info;
4120 const struct wined3d_gl_info *gl_info;
4121 struct wined3d_context *context;
4122 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4123 HRESULT hr;
4125 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4127 if(pVertexDecl) {
4128 ERR("Output vertex declaration not implemented yet\n");
4131 /* Need any context to write to the vbo. */
4132 context = context_acquire(This, NULL);
4133 gl_info = context->gl_info;
4135 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4136 * control the streamIsUP flag, thus restore it afterwards.
4138 This->stateBlock->streamIsUP = FALSE;
4139 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4140 This->stateBlock->streamIsUP = streamWasUP;
4142 if(vbo || SrcStartIndex) {
4143 unsigned int i;
4144 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4145 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4147 * Also get the start index in, but only loop over all elements if there's something to add at all.
4149 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4151 struct wined3d_stream_info_element *e;
4153 if (!(stream_info.use_map & (1 << i))) continue;
4155 e = &stream_info.elements[i];
4156 if (e->buffer_object)
4158 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4159 e->buffer_object = 0;
4160 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4161 ENTER_GL();
4162 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4163 vb->buffer_object = 0;
4164 LEAVE_GL();
4166 if (e->data) e->data += e->stride * SrcStartIndex;
4170 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4171 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4173 context_release(context);
4175 return hr;
4178 /*****
4179 * Get / Set Texture Stage States
4180 * TODO: Verify against dx9 definitions
4181 *****/
4182 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4184 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4185 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4187 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4189 if (Stage >= gl_info->limits.texture_stages)
4191 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4192 Stage, gl_info->limits.texture_stages - 1);
4193 return WINED3D_OK;
4196 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4197 This->updateStateBlock->textureState[Stage][Type] = Value;
4199 if (This->isRecordingState) {
4200 TRACE("Recording... not performing anything\n");
4201 return WINED3D_OK;
4204 /* Checked after the assignments to allow proper stateblock recording */
4205 if(oldValue == Value) {
4206 TRACE("App is setting the old value over, nothing to do\n");
4207 return WINED3D_OK;
4210 if(Stage > This->stateBlock->lowest_disabled_stage &&
4211 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4212 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4213 * Changes in other states are important on disabled stages too
4215 return WINED3D_OK;
4218 if(Type == WINED3DTSS_COLOROP) {
4219 unsigned int i;
4221 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4222 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4223 * they have to be disabled
4225 * The current stage is dirtified below.
4227 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4228 TRACE("Additionally dirtifying stage %u\n", i);
4229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4231 This->stateBlock->lowest_disabled_stage = Stage;
4232 TRACE("New lowest disabled: %u\n", Stage);
4233 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4234 /* Previously disabled stage enabled. Stages above it may need enabling
4235 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4236 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4238 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4241 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4243 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4244 break;
4246 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4249 This->stateBlock->lowest_disabled_stage = i;
4250 TRACE("New lowest disabled: %u\n", i);
4254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4256 return WINED3D_OK;
4259 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4261 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4262 *pValue = This->updateStateBlock->textureState[Stage][Type];
4263 return WINED3D_OK;
4266 /*****
4267 * Get / Set Texture
4268 *****/
4269 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4270 DWORD stage, IWineD3DBaseTexture *texture)
4272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4273 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4274 IWineD3DBaseTexture *prev;
4276 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4278 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4279 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4281 /* Windows accepts overflowing this array... we do not. */
4282 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4284 WARN("Ignoring invalid stage %u.\n", stage);
4285 return WINED3D_OK;
4288 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4289 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4291 WARN("Rejecting attempt to set scratch texture.\n");
4292 return WINED3DERR_INVALIDCALL;
4295 This->updateStateBlock->changed.textures |= 1 << stage;
4297 prev = This->updateStateBlock->textures[stage];
4298 TRACE("Previous texture %p.\n", prev);
4300 if (texture == prev)
4302 TRACE("App is setting the same texture again, nothing to do.\n");
4303 return WINED3D_OK;
4306 TRACE("Setting new texture to %p.\n", texture);
4307 This->updateStateBlock->textures[stage] = texture;
4309 if (This->isRecordingState)
4311 TRACE("Recording... not performing anything\n");
4313 if (texture) IWineD3DBaseTexture_AddRef(texture);
4314 if (prev) IWineD3DBaseTexture_Release(prev);
4316 return WINED3D_OK;
4319 if (texture)
4321 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4322 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4323 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4325 IWineD3DBaseTexture_AddRef(texture);
4327 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4332 if (!prev && stage < gl_info->limits.texture_stages)
4334 /* The source arguments for color and alpha ops have different
4335 * meanings when a NULL texture is bound, so the COLOROP and
4336 * ALPHAOP have to be dirtified. */
4337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4341 if (bind_count == 1) t->baseTexture.sampler = stage;
4344 if (prev)
4346 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4347 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4349 IWineD3DBaseTexture_Release(prev);
4351 if (!texture && stage < gl_info->limits.texture_stages)
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4357 if (bind_count && t->baseTexture.sampler == stage)
4359 unsigned int i;
4361 /* Search for other stages the texture is bound to. Shouldn't
4362 * happen if applications bind textures to a single stage only. */
4363 TRACE("Searching for other stages the texture is bound to.\n");
4364 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4366 if (This->updateStateBlock->textures[i] == prev)
4368 TRACE("Texture is also bound to stage %u.\n", i);
4369 t->baseTexture.sampler = i;
4370 break;
4376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4378 return WINED3D_OK;
4381 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4384 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4386 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4387 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4390 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4391 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4392 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4395 *ppTexture=This->stateBlock->textures[Stage];
4396 if (*ppTexture)
4397 IWineD3DBaseTexture_AddRef(*ppTexture);
4399 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4401 return WINED3D_OK;
4404 /*****
4405 * Get Back Buffer
4406 *****/
4407 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4408 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4410 IWineD3DSwapChain *swapchain;
4411 HRESULT hr;
4413 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4414 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4416 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4417 if (FAILED(hr))
4419 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4420 return hr;
4423 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4424 IWineD3DSwapChain_Release(swapchain);
4425 if (FAILED(hr))
4427 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4428 return hr;
4431 return WINED3D_OK;
4434 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 WARN("(%p) : stub, calling idirect3d for now\n", This);
4437 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4440 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DSwapChain *swapChain;
4443 HRESULT hr;
4445 if(iSwapChain > 0) {
4446 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4447 if (hr == WINED3D_OK) {
4448 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4449 IWineD3DSwapChain_Release(swapChain);
4450 } else {
4451 FIXME("(%p) Error getting display mode\n", This);
4453 } else {
4454 /* Don't read the real display mode,
4455 but return the stored mode instead. X11 can't change the color
4456 depth, and some apps are pretty angry if they SetDisplayMode from
4457 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4459 Also don't relay to the swapchain because with ddraw it's possible
4460 that there isn't a swapchain at all */
4461 pMode->Width = This->ddraw_width;
4462 pMode->Height = This->ddraw_height;
4463 pMode->Format = This->ddraw_format;
4464 pMode->RefreshRate = 0;
4465 hr = WINED3D_OK;
4468 return hr;
4471 /*****
4472 * Stateblock related functions
4473 *****/
4475 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 IWineD3DStateBlock *stateblock;
4478 HRESULT hr;
4480 TRACE("(%p)\n", This);
4482 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4484 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4485 if (FAILED(hr)) return hr;
4487 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4488 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4489 This->isRecordingState = TRUE;
4491 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4493 return WINED3D_OK;
4496 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4500 if (!This->isRecordingState) {
4501 WARN("(%p) not recording! returning error\n", This);
4502 *ppStateBlock = NULL;
4503 return WINED3DERR_INVALIDCALL;
4506 stateblock_init_contained_states(object);
4508 *ppStateBlock = (IWineD3DStateBlock*) object;
4509 This->isRecordingState = FALSE;
4510 This->updateStateBlock = This->stateBlock;
4511 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4512 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4513 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4514 return WINED3D_OK;
4517 /*****
4518 * Scene related functions
4519 *****/
4520 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4521 /* At the moment we have no need for any functionality at the beginning
4522 of a scene */
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 TRACE("(%p)\n", This);
4526 if(This->inScene) {
4527 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4528 return WINED3DERR_INVALIDCALL;
4530 This->inScene = TRUE;
4531 return WINED3D_OK;
4534 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4537 struct wined3d_context *context;
4539 TRACE("(%p)\n", This);
4541 if(!This->inScene) {
4542 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4543 return WINED3DERR_INVALIDCALL;
4546 context = context_acquire(This, NULL);
4547 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4548 wglFlush();
4549 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4550 * fails. */
4551 context_release(context);
4553 This->inScene = FALSE;
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4558 const RECT *pSourceRect, const RECT *pDestRect,
4559 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4561 IWineD3DSwapChain *swapChain = NULL;
4562 int i;
4563 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4565 TRACE("iface %p.\n", iface);
4567 for(i = 0 ; i < swapchains ; i ++) {
4569 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4570 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4571 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4572 IWineD3DSwapChain_Release(swapChain);
4575 return WINED3D_OK;
4578 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4579 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR color, float Z, DWORD Stencil)
4581 const float c[] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4584 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), color (0x%08x), Z (%f), Stencil (%d)\n", This,
4585 Count, pRects, Flags, color, Z, Stencil);
4587 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4589 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4590 /* TODO: What about depth stencil buffers without stencil bits? */
4591 return WINED3DERR_INVALIDCALL;
4594 return device_clear_render_targets(This, This->adapter->gl_info.limits.buffers,
4595 This->render_targets, Count, pRects, Flags, c, Z, Stencil);
4598 /*****
4599 * Drawing functions
4600 *****/
4602 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4603 WINED3DPRIMITIVETYPE primitive_type)
4605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4609 This->updateStateBlock->changed.primitive_type = TRUE;
4610 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4613 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4614 WINED3DPRIMITIVETYPE *primitive_type)
4616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4620 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4622 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4625 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4631 if(!This->stateBlock->vertexDecl) {
4632 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4633 return WINED3DERR_INVALIDCALL;
4636 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4637 if(This->stateBlock->streamIsUP) {
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4639 This->stateBlock->streamIsUP = FALSE;
4642 if(This->stateBlock->loadBaseVertexIndex != 0) {
4643 This->stateBlock->loadBaseVertexIndex = 0;
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4646 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4647 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4648 return WINED3D_OK;
4651 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4654 UINT idxStride = 2;
4655 IWineD3DBuffer *pIB;
4656 GLuint vbo;
4658 pIB = This->stateBlock->pIndexData;
4659 if (!pIB) {
4660 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4661 * without an index buffer set. (The first time at least...)
4662 * D3D8 simply dies, but I doubt it can do much harm to return
4663 * D3DERR_INVALIDCALL there as well. */
4664 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4665 return WINED3DERR_INVALIDCALL;
4668 if(!This->stateBlock->vertexDecl) {
4669 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4670 return WINED3DERR_INVALIDCALL;
4673 if(This->stateBlock->streamIsUP) {
4674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4675 This->stateBlock->streamIsUP = FALSE;
4677 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4679 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4681 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4682 idxStride = 2;
4683 } else {
4684 idxStride = 4;
4687 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4688 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4692 drawPrimitive(iface, index_count, startIndex, idxStride,
4693 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4695 return WINED3D_OK;
4698 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4699 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4702 IWineD3DBuffer *vb;
4704 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4705 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4707 if(!This->stateBlock->vertexDecl) {
4708 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4709 return WINED3DERR_INVALIDCALL;
4712 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4713 vb = This->stateBlock->streamSource[0];
4714 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4715 if (vb) IWineD3DBuffer_Release(vb);
4716 This->stateBlock->streamOffset[0] = 0;
4717 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4718 This->stateBlock->streamIsUP = TRUE;
4719 This->stateBlock->loadBaseVertexIndex = 0;
4721 /* TODO: Only mark dirty if drawing from a different UP address */
4722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4724 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4726 /* MSDN specifies stream zero settings must be set to NULL */
4727 This->stateBlock->streamStride[0] = 0;
4728 This->stateBlock->streamSource[0] = NULL;
4730 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4731 * the new stream sources or use UP drawing again
4733 return WINED3D_OK;
4736 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4737 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4738 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4740 int idxStride;
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 IWineD3DBuffer *vb;
4743 IWineD3DBuffer *ib;
4745 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4746 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4748 if(!This->stateBlock->vertexDecl) {
4749 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4750 return WINED3DERR_INVALIDCALL;
4753 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4754 idxStride = 2;
4755 } else {
4756 idxStride = 4;
4759 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4760 vb = This->stateBlock->streamSource[0];
4761 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4762 if (vb) IWineD3DBuffer_Release(vb);
4763 This->stateBlock->streamIsUP = TRUE;
4764 This->stateBlock->streamOffset[0] = 0;
4765 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4767 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4768 This->stateBlock->baseVertexIndex = 0;
4769 This->stateBlock->loadBaseVertexIndex = 0;
4770 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4774 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4776 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4777 This->stateBlock->streamSource[0] = NULL;
4778 This->stateBlock->streamStride[0] = 0;
4779 ib = This->stateBlock->pIndexData;
4780 if(ib) {
4781 IWineD3DBuffer_Release(ib);
4782 This->stateBlock->pIndexData = NULL;
4784 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4785 * SetStreamSource to specify a vertex buffer
4788 return WINED3D_OK;
4791 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4792 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4796 /* Mark the state dirty until we have nicer tracking
4797 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4798 * that value.
4800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4802 This->stateBlock->baseVertexIndex = 0;
4803 This->up_strided = DrawPrimStrideData;
4804 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4805 This->up_strided = NULL;
4806 return WINED3D_OK;
4809 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4810 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4811 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4814 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4816 /* Mark the state dirty until we have nicer tracking
4817 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4818 * that value.
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4822 This->stateBlock->streamIsUP = TRUE;
4823 This->stateBlock->baseVertexIndex = 0;
4824 This->up_strided = DrawPrimStrideData;
4825 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4826 This->up_strided = NULL;
4827 return WINED3D_OK;
4830 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4831 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4832 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4834 WINED3DLOCKED_BOX src;
4835 WINED3DLOCKED_BOX dst;
4836 HRESULT hr;
4838 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4839 iface, pSourceVolume, pDestinationVolume);
4841 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4842 * dirtification to improve loading performance.
4844 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4845 if(FAILED(hr)) return hr;
4846 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4847 if(FAILED(hr)) {
4848 IWineD3DVolume_UnlockBox(pSourceVolume);
4849 return hr;
4852 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4854 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4855 if(FAILED(hr)) {
4856 IWineD3DVolume_UnlockBox(pSourceVolume);
4857 } else {
4858 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4860 return hr;
4863 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4864 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4866 unsigned int level_count, i;
4867 WINED3DRESOURCETYPE type;
4868 HRESULT hr;
4870 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4872 /* Verify that the source and destination textures are non-NULL. */
4873 if (!src_texture || !dst_texture)
4875 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4876 return WINED3DERR_INVALIDCALL;
4879 if (src_texture == dst_texture)
4881 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4882 return WINED3DERR_INVALIDCALL;
4885 /* Verify that the source and destination textures are the same type. */
4886 type = IWineD3DBaseTexture_GetType(src_texture);
4887 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4889 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4890 return WINED3DERR_INVALIDCALL;
4893 /* Check that both textures have the identical numbers of levels. */
4894 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4895 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4897 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4898 return WINED3DERR_INVALIDCALL;
4901 /* Make sure that the destination texture is loaded. */
4902 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4904 /* Update every surface level of the texture. */
4905 switch (type)
4907 case WINED3DRTYPE_TEXTURE:
4909 IWineD3DSurface *src_surface;
4910 IWineD3DSurface *dst_surface;
4912 for (i = 0; i < level_count; ++i)
4914 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4915 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4916 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4917 IWineD3DSurface_Release(dst_surface);
4918 IWineD3DSurface_Release(src_surface);
4919 if (FAILED(hr))
4921 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4922 return hr;
4925 break;
4928 case WINED3DRTYPE_CUBETEXTURE:
4930 IWineD3DSurface *src_surface;
4931 IWineD3DSurface *dst_surface;
4932 WINED3DCUBEMAP_FACES face;
4934 for (i = 0; i < level_count; ++i)
4936 /* Update each cube face. */
4937 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4939 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4940 face, i, &src_surface);
4941 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4942 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4943 face, i, &dst_surface);
4944 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4945 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4946 IWineD3DSurface_Release(dst_surface);
4947 IWineD3DSurface_Release(src_surface);
4948 if (FAILED(hr))
4950 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4951 return hr;
4955 break;
4958 case WINED3DRTYPE_VOLUMETEXTURE:
4960 IWineD3DVolume *src_volume;
4961 IWineD3DVolume *dst_volume;
4963 for (i = 0; i < level_count; ++i)
4965 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4966 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4967 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4968 IWineD3DVolume_Release(dst_volume);
4969 IWineD3DVolume_Release(src_volume);
4970 if (FAILED(hr))
4972 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4973 return hr;
4976 break;
4979 default:
4980 FIXME("Unsupported texture type %#x.\n", type);
4981 return WINED3DERR_INVALIDCALL;
4984 return WINED3D_OK;
4987 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4988 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4990 IWineD3DSwapChain *swapchain;
4991 HRESULT hr;
4993 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
4995 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4996 if (FAILED(hr)) return hr;
4998 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
4999 IWineD3DSwapChain_Release(swapchain);
5001 return hr;
5004 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5006 IWineD3DBaseTextureImpl *texture;
5007 DWORD i;
5009 TRACE("(%p) : %p\n", This, pNumPasses);
5011 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5012 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5013 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5014 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5016 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5017 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5018 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5021 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5022 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5024 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5025 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5026 return E_FAIL;
5028 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5029 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5030 return E_FAIL;
5032 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5033 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5034 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5035 return E_FAIL;
5039 /* return a sensible default */
5040 *pNumPasses = 1;
5042 TRACE("returning D3D_OK\n");
5043 return WINED3D_OK;
5046 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5048 int i;
5050 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5052 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5053 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5054 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5056 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5061 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 int j;
5064 UINT NewSize;
5065 PALETTEENTRY **palettes;
5067 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5069 if (PaletteNumber >= MAX_PALETTES) {
5070 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5071 return WINED3DERR_INVALIDCALL;
5074 if (PaletteNumber >= This->NumberOfPalettes) {
5075 NewSize = This->NumberOfPalettes;
5076 do {
5077 NewSize *= 2;
5078 } while(PaletteNumber >= NewSize);
5079 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5080 if (!palettes) {
5081 ERR("Out of memory!\n");
5082 return E_OUTOFMEMORY;
5084 This->palettes = palettes;
5085 This->NumberOfPalettes = NewSize;
5088 if (!This->palettes[PaletteNumber]) {
5089 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5090 if (!This->palettes[PaletteNumber]) {
5091 ERR("Out of memory!\n");
5092 return E_OUTOFMEMORY;
5096 for (j = 0; j < 256; ++j) {
5097 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5098 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5099 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5100 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5102 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5103 TRACE("(%p) : returning\n", This);
5104 return WINED3D_OK;
5107 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 int j;
5110 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5111 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5112 /* What happens in such situation isn't documented; Native seems to silently abort
5113 on such conditions. Return Invalid Call. */
5114 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5115 return WINED3DERR_INVALIDCALL;
5117 for (j = 0; j < 256; ++j) {
5118 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5119 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5120 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5121 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5123 TRACE("(%p) : returning\n", This);
5124 return WINED3D_OK;
5127 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5130 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5131 (tested with reference rasterizer). Return Invalid Call. */
5132 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5133 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5134 return WINED3DERR_INVALIDCALL;
5136 /*TODO: stateblocks */
5137 if (This->currentPalette != PaletteNumber) {
5138 This->currentPalette = PaletteNumber;
5139 dirtify_p8_texture_samplers(This);
5141 TRACE("(%p) : returning\n", This);
5142 return WINED3D_OK;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5147 if (PaletteNumber == NULL) {
5148 WARN("(%p) : returning Invalid Call\n", This);
5149 return WINED3DERR_INVALIDCALL;
5151 /*TODO: stateblocks */
5152 *PaletteNumber = This->currentPalette;
5153 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5154 return WINED3D_OK;
5157 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5159 static BOOL warned;
5160 if (!warned)
5162 FIXME("(%p) : stub\n", This);
5163 warned = TRUE;
5166 This->softwareVertexProcessing = bSoftware;
5167 return WINED3D_OK;
5171 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5173 static BOOL warned;
5174 if (!warned)
5176 FIXME("(%p) : stub\n", This);
5177 warned = TRUE;
5179 return This->softwareVertexProcessing;
5182 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5183 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5185 IWineD3DSwapChain *swapchain;
5186 HRESULT hr;
5188 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5189 iface, swapchain_idx, raster_status);
5191 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5192 if (FAILED(hr))
5194 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5195 return hr;
5198 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5199 IWineD3DSwapChain_Release(swapchain);
5200 if (FAILED(hr))
5202 WARN("Failed to get raster status, hr %#x.\n", hr);
5203 return hr;
5206 return WINED3D_OK;
5209 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5211 static BOOL warned;
5212 if(nSegments != 0.0f) {
5213 if (!warned)
5215 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5216 warned = TRUE;
5219 return WINED3D_OK;
5222 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5224 static BOOL warned;
5225 if (!warned)
5227 FIXME("iface %p stub!\n", iface);
5228 warned = TRUE;
5230 return 0.0f;
5233 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5234 IWineD3DSurface *src_surface, const RECT *src_rect,
5235 IWineD3DSurface *dst_surface, const POINT *dst_point)
5237 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5238 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240 const struct wined3d_format_desc *src_format;
5241 const struct wined3d_format_desc *dst_format;
5242 const struct wined3d_gl_info *gl_info;
5243 struct wined3d_context *context;
5244 const unsigned char *data;
5245 UINT update_w, update_h;
5246 CONVERT_TYPES convert;
5247 UINT src_w, src_h;
5248 UINT dst_x, dst_y;
5249 DWORD sampler;
5250 struct wined3d_format_desc desc;
5252 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5253 iface, src_surface, wine_dbgstr_rect(src_rect),
5254 dst_surface, wine_dbgstr_point(dst_point));
5256 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5258 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5259 src_surface, dst_surface);
5260 return WINED3DERR_INVALIDCALL;
5263 src_format = src_impl->resource.format_desc;
5264 dst_format = dst_impl->resource.format_desc;
5266 if (src_format->format != dst_format->format)
5268 WARN("Source and destination surfaces should have the same format.\n");
5269 return WINED3DERR_INVALIDCALL;
5272 dst_x = dst_point ? dst_point->x : 0;
5273 dst_y = dst_point ? dst_point->y : 0;
5275 /* This call loads the OpenGL surface directly, instead of copying the
5276 * surface to the destination's sysmem copy. If surface conversion is
5277 * needed, use BltFast instead to copy in sysmem and use regular surface
5278 * loading. */
5279 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5280 if (convert != NO_CONVERSION || desc.convert)
5281 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5283 context = context_acquire(This, NULL);
5284 gl_info = context->gl_info;
5286 ENTER_GL();
5287 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5288 checkGLcall("glActiveTextureARB");
5289 LEAVE_GL();
5291 /* Make sure the surface is loaded and up to date */
5292 surface_internal_preload(dst_impl, SRGB_RGB);
5293 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5295 src_w = src_impl->currentDesc.Width;
5296 src_h = src_impl->currentDesc.Height;
5297 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5298 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5300 data = IWineD3DSurface_GetData(src_surface);
5301 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5303 ENTER_GL();
5305 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5307 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5308 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5309 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5311 if (src_rect)
5313 data += (src_rect->top / src_format->block_height) * src_pitch;
5314 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5317 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5318 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5319 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5321 if (row_length == src_pitch)
5323 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5324 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5326 else
5328 UINT row, y;
5330 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5331 * can't use the unpack row length like below. */
5332 for (row = 0, y = dst_y; row < row_count; ++row)
5334 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5335 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5336 y += src_format->block_height;
5337 data += src_pitch;
5340 checkGLcall("glCompressedTexSubImage2DARB");
5342 else
5344 if (src_rect)
5346 data += src_rect->top * src_w * src_format->byte_count;
5347 data += src_rect->left * src_format->byte_count;
5350 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5351 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5352 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5354 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5355 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5356 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5357 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5358 checkGLcall("glTexSubImage2D");
5361 LEAVE_GL();
5362 context_release(context);
5364 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5365 sampler = This->rev_tex_unit_map[0];
5366 if (sampler != WINED3D_UNMAPPED_STAGE)
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5371 return WINED3D_OK;
5374 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 struct WineD3DRectPatch *patch;
5377 GLenum old_primitive_type;
5378 unsigned int i;
5379 struct list *e;
5380 BOOL found;
5381 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5383 if(!(Handle || pRectPatchInfo)) {
5384 /* TODO: Write a test for the return value, thus the FIXME */
5385 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5386 return WINED3DERR_INVALIDCALL;
5389 if(Handle) {
5390 i = PATCHMAP_HASHFUNC(Handle);
5391 found = FALSE;
5392 LIST_FOR_EACH(e, &This->patches[i]) {
5393 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5394 if(patch->Handle == Handle) {
5395 found = TRUE;
5396 break;
5400 if(!found) {
5401 TRACE("Patch does not exist. Creating a new one\n");
5402 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5403 patch->Handle = Handle;
5404 list_add_head(&This->patches[i], &patch->entry);
5405 } else {
5406 TRACE("Found existing patch %p\n", patch);
5408 } else {
5409 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5410 * attributes we have to tesselate, read back, and draw. This needs a patch
5411 * management structure instance. Create one.
5413 * A possible improvement is to check if a vertex shader is used, and if not directly
5414 * draw the patch.
5416 FIXME("Drawing an uncached patch. This is slow\n");
5417 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5420 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5421 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5422 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5423 HRESULT hr;
5424 TRACE("Tesselation density or patch info changed, retesselating\n");
5426 if(pRectPatchInfo) {
5427 patch->RectPatchInfo = *pRectPatchInfo;
5429 patch->numSegs[0] = pNumSegs[0];
5430 patch->numSegs[1] = pNumSegs[1];
5431 patch->numSegs[2] = pNumSegs[2];
5432 patch->numSegs[3] = pNumSegs[3];
5434 hr = tesselate_rectpatch(This, patch);
5435 if(FAILED(hr)) {
5436 WARN("Patch tesselation failed\n");
5438 /* Do not release the handle to store the params of the patch */
5439 if(!Handle) {
5440 HeapFree(GetProcessHeap(), 0, patch);
5442 return hr;
5446 This->currentPatch = patch;
5447 old_primitive_type = This->stateBlock->gl_primitive_type;
5448 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5449 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5450 This->stateBlock->gl_primitive_type = old_primitive_type;
5451 This->currentPatch = NULL;
5453 /* Destroy uncached patches */
5454 if(!Handle) {
5455 HeapFree(GetProcessHeap(), 0, patch->mem);
5456 HeapFree(GetProcessHeap(), 0, patch);
5458 return WINED3D_OK;
5461 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5462 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5464 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5465 iface, handle, segment_count, patch_info);
5467 return WINED3D_OK;
5470 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5472 int i;
5473 struct WineD3DRectPatch *patch;
5474 struct list *e;
5475 TRACE("(%p) Handle(%d)\n", This, Handle);
5477 i = PATCHMAP_HASHFUNC(Handle);
5478 LIST_FOR_EACH(e, &This->patches[i]) {
5479 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5480 if(patch->Handle == Handle) {
5481 TRACE("Deleting patch %p\n", patch);
5482 list_remove(&patch->entry);
5483 HeapFree(GetProcessHeap(), 0, patch->mem);
5484 HeapFree(GetProcessHeap(), 0, patch);
5485 return WINED3D_OK;
5489 /* TODO: Write a test for the return value */
5490 FIXME("Attempt to destroy nonexistent patch\n");
5491 return WINED3DERR_INVALIDCALL;
5494 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5495 IWineD3DSurface *surface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5497 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5498 WINEDDBLTFX BltFx;
5500 TRACE("iface %p, surface %p, rect %s, color 0x%08x.\n",
5501 iface, surface, wine_dbgstr_rect((const RECT *)pRect), color);
5503 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5505 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5506 return WINED3DERR_INVALIDCALL;
5509 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5510 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5512 return device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &s,
5513 !!pRect, pRect, WINED3DCLEAR_TARGET, c, 0.0f, 0);
5515 else
5517 /* Just forward this to the DirectDraw blitting engine */
5518 memset(&BltFx, 0, sizeof(BltFx));
5519 BltFx.dwSize = sizeof(BltFx);
5520 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, s->resource.format_desc->format);
5521 return IWineD3DSurface_Blt(surface, (const RECT *)pRect, NULL, NULL,
5522 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5526 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5527 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5529 IWineD3DResource *resource;
5530 IWineD3DSurfaceImpl *surface;
5531 HRESULT hr;
5533 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5534 if (FAILED(hr))
5536 ERR("Failed to get resource, hr %#x\n", hr);
5537 return;
5540 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5542 FIXME("Only supported on surface resources\n");
5543 IWineD3DResource_Release(resource);
5544 return;
5547 surface = (IWineD3DSurfaceImpl *)resource;
5549 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5551 device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &surface,
5552 0, NULL, WINED3DCLEAR_TARGET, color, 0.0f, 0);
5554 else
5556 WINEDDBLTFX BltFx;
5557 WINED3DCOLOR c;
5559 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5561 c = ((DWORD)(color[2] * 255.0f));
5562 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5563 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5564 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5566 /* Just forward this to the DirectDraw blitting engine */
5567 memset(&BltFx, 0, sizeof(BltFx));
5568 BltFx.dwSize = sizeof(BltFx);
5569 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5570 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5571 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5572 if (FAILED(hr))
5574 ERR("Blt failed, hr %#x\n", hr);
5578 IWineD3DResource_Release(resource);
5581 /* rendertarget and depth stencil functions */
5582 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5583 DWORD render_target_idx, IWineD3DSurface **render_target)
5585 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5587 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5588 iface, render_target_idx, render_target);
5590 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5592 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5593 return WINED3DERR_INVALIDCALL;
5596 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5597 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5599 TRACE("Returning render target %p.\n", *render_target);
5601 return WINED3D_OK;
5604 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5605 IWineD3DSurface *front, IWineD3DSurface *back)
5607 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5608 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5609 IWineD3DSwapChainImpl *swapchain;
5610 HRESULT hr;
5612 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5614 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5616 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5617 return hr;
5620 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5622 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5623 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5624 return WINED3DERR_INVALIDCALL;
5627 if (back_impl)
5629 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5631 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5632 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5633 return WINED3DERR_INVALIDCALL;
5636 if (!swapchain->back_buffers)
5638 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5639 if (!swapchain->back_buffers)
5641 ERR("Failed to allocate back buffer array memory.\n");
5642 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5643 return E_OUTOFMEMORY;
5648 if (swapchain->front_buffer != front_impl)
5650 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5652 if (swapchain->front_buffer)
5654 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5655 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5657 swapchain->front_buffer = front_impl;
5659 if (front)
5661 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5662 front_impl->Flags |= SFLAG_SWAPCHAIN;
5666 if (swapchain->back_buffers[0] != back_impl)
5668 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5670 if (swapchain->back_buffers[0])
5672 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5673 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5675 swapchain->back_buffers[0] = back_impl;
5677 if (back)
5679 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5680 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5681 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5682 swapchain->presentParms.BackBufferCount = 1;
5684 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5685 back_impl->Flags |= SFLAG_SWAPCHAIN;
5687 else
5689 swapchain->presentParms.BackBufferCount = 0;
5690 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5691 swapchain->back_buffers = NULL;
5695 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5696 return WINED3D_OK;
5699 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5701 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5703 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5705 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5706 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5707 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5708 IWineD3DSurface_AddRef(*depth_stencil);
5710 return WINED3D_OK;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5714 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5716 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5718 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5719 iface, render_target_idx, render_target, set_viewport);
5721 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5723 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5724 return WINED3DERR_INVALIDCALL;
5727 if (render_target == (IWineD3DSurface *)device->render_targets[render_target_idx])
5729 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5730 return WINED3D_OK;
5733 /* Render target 0 can't be set to NULL. */
5734 if (!render_target && !render_target_idx)
5736 WARN("Trying to set render target 0 to NULL.\n");
5737 return WINED3DERR_INVALIDCALL;
5740 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5742 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5743 return WINED3DERR_INVALIDCALL;
5746 if (render_target)
5747 IWineD3DSurface_AddRef(render_target);
5748 if (device->render_targets[render_target_idx])
5749 IWineD3DSurface_Release((IWineD3DSurface *)device->render_targets[render_target_idx]);
5750 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5752 /* Render target 0 is special. */
5753 if (!render_target_idx && set_viewport)
5755 /* Set the viewport and scissor rectangles, if requested. Tests show
5756 * that stateblock recording is ignored, the change goes directly
5757 * into the primary stateblock. */
5758 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5759 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5760 device->stateBlock->viewport.X = 0;
5761 device->stateBlock->viewport.Y = 0;
5762 device->stateBlock->viewport.MaxZ = 1.0f;
5763 device->stateBlock->viewport.MinZ = 0.0f;
5764 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5766 device->stateBlock->scissorRect.top = 0;
5767 device->stateBlock->scissorRect.left = 0;
5768 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5769 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5770 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5773 return WINED3D_OK;
5776 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5779 IWineD3DSurfaceImpl *tmp;
5781 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5783 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5785 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5786 return WINED3D_OK;
5789 if (This->depth_stencil)
5791 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5792 || This->depth_stencil->Flags & SFLAG_DISCARD)
5794 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5795 This->depth_stencil->currentDesc.Width,
5796 This->depth_stencil->currentDesc.Height);
5797 if (This->depth_stencil == This->onscreen_depth_stencil)
5799 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5800 This->onscreen_depth_stencil = NULL;
5805 tmp = This->depth_stencil;
5806 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5807 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5808 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5810 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5812 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5818 return WINED3D_OK;
5821 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5822 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5825 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5826 WINED3DLOCKED_RECT lockedRect;
5828 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5829 iface, XHotSpot, YHotSpot, cursor_image);
5831 /* some basic validation checks */
5832 if (This->cursorTexture)
5834 struct wined3d_context *context = context_acquire(This, NULL);
5835 ENTER_GL();
5836 glDeleteTextures(1, &This->cursorTexture);
5837 LEAVE_GL();
5838 context_release(context);
5839 This->cursorTexture = 0;
5842 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5843 This->haveHardwareCursor = TRUE;
5844 else
5845 This->haveHardwareCursor = FALSE;
5847 if (cursor_image)
5849 WINED3DLOCKED_RECT rect;
5851 /* MSDN: Cursor must be A8R8G8B8 */
5852 if (s->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5854 WARN("surface %p has an invalid format.\n", cursor_image);
5855 return WINED3DERR_INVALIDCALL;
5858 /* MSDN: Cursor must be smaller than the display mode */
5859 if (s->currentDesc.Width > This->ddraw_width
5860 || s->currentDesc.Height > This->ddraw_height)
5862 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5863 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5864 return WINED3DERR_INVALIDCALL;
5867 if (!This->haveHardwareCursor) {
5868 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5870 /* Do not store the surface's pointer because the application may
5871 * release it after setting the cursor image. Windows doesn't
5872 * addref the set surface, so we can't do this either without
5873 * creating circular refcount dependencies. Copy out the gl texture
5874 * instead.
5876 This->cursorWidth = s->currentDesc.Width;
5877 This->cursorHeight = s->currentDesc.Height;
5878 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5880 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5881 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5882 struct wined3d_context *context;
5883 char *mem, *bits = rect.pBits;
5884 GLint intfmt = format_desc->glInternal;
5885 GLint format = format_desc->glFormat;
5886 GLint type = format_desc->glType;
5887 INT height = This->cursorHeight;
5888 INT width = This->cursorWidth;
5889 INT bpp = format_desc->byte_count;
5890 DWORD sampler;
5891 INT i;
5893 /* Reformat the texture memory (pitch and width can be
5894 * different) */
5895 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5896 for(i = 0; i < height; i++)
5897 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5898 IWineD3DSurface_UnlockRect(cursor_image);
5900 context = context_acquire(This, NULL);
5902 ENTER_GL();
5904 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5906 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5907 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5910 /* Make sure that a proper texture unit is selected */
5911 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5912 checkGLcall("glActiveTextureARB");
5913 sampler = This->rev_tex_unit_map[0];
5914 if (sampler != WINED3D_UNMAPPED_STAGE)
5916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5918 /* Create a new cursor texture */
5919 glGenTextures(1, &This->cursorTexture);
5920 checkGLcall("glGenTextures");
5921 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5922 checkGLcall("glBindTexture");
5923 /* Copy the bitmap memory into the cursor texture */
5924 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5925 HeapFree(GetProcessHeap(), 0, mem);
5926 checkGLcall("glTexImage2D");
5928 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5930 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5931 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5934 LEAVE_GL();
5936 context_release(context);
5938 else
5940 FIXME("A cursor texture was not returned.\n");
5941 This->cursorTexture = 0;
5944 else
5946 /* Draw a hardware cursor */
5947 ICONINFO cursorInfo;
5948 HCURSOR cursor;
5949 /* Create and clear maskBits because it is not needed for
5950 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5951 * chunks. */
5952 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5953 (s->currentDesc.Width * s->currentDesc.Height / 8));
5954 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5955 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5956 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5958 cursorInfo.fIcon = FALSE;
5959 cursorInfo.xHotspot = XHotSpot;
5960 cursorInfo.yHotspot = YHotSpot;
5961 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5962 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5963 IWineD3DSurface_UnlockRect(cursor_image);
5964 /* Create our cursor and clean up. */
5965 cursor = CreateIconIndirect(&cursorInfo);
5966 SetCursor(cursor);
5967 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5968 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5969 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5970 This->hardwareCursor = cursor;
5971 HeapFree(GetProcessHeap(), 0, maskBits);
5975 This->xHotSpot = XHotSpot;
5976 This->yHotSpot = YHotSpot;
5977 return WINED3D_OK;
5980 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5982 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5984 This->xScreenSpace = XScreenSpace;
5985 This->yScreenSpace = YScreenSpace;
5987 return;
5991 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5993 BOOL oldVisible = This->bCursorVisible;
5994 POINT pt;
5996 TRACE("(%p) : visible(%d)\n", This, bShow);
5999 * When ShowCursor is first called it should make the cursor appear at the OS's last
6000 * known cursor position. Because of this, some applications just repetitively call
6001 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6003 GetCursorPos(&pt);
6004 This->xScreenSpace = pt.x;
6005 This->yScreenSpace = pt.y;
6007 if (This->haveHardwareCursor) {
6008 This->bCursorVisible = bShow;
6009 if (bShow)
6010 SetCursor(This->hardwareCursor);
6011 else
6012 SetCursor(NULL);
6014 else
6016 if (This->cursorTexture)
6017 This->bCursorVisible = bShow;
6020 return oldVisible;
6023 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6024 TRACE("checking resource %p for eviction\n", resource);
6025 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6026 TRACE("Evicting %p\n", resource);
6027 IWineD3DResource_UnLoad(resource);
6029 IWineD3DResource_Release(resource);
6030 return S_OK;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6035 TRACE("iface %p.\n", iface);
6037 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6038 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6039 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6041 return WINED3D_OK;
6044 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6046 IWineD3DDeviceImpl *device = surface->resource.device;
6047 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6049 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6050 if(surface->Flags & SFLAG_DIBSECTION) {
6051 /* Release the DC */
6052 SelectObject(surface->hDC, surface->dib.holdbitmap);
6053 DeleteDC(surface->hDC);
6054 /* Release the DIB section */
6055 DeleteObject(surface->dib.DIBsection);
6056 surface->dib.bitmap_data = NULL;
6057 surface->resource.allocatedMemory = NULL;
6058 surface->Flags &= ~SFLAG_DIBSECTION;
6060 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6061 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6062 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6063 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6065 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6066 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6067 } else {
6068 surface->pow2Width = surface->pow2Height = 1;
6069 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6070 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6073 if (surface->texture_name)
6075 struct wined3d_context *context = context_acquire(device, NULL);
6076 ENTER_GL();
6077 glDeleteTextures(1, &surface->texture_name);
6078 LEAVE_GL();
6079 context_release(context);
6080 surface->texture_name = 0;
6081 surface->Flags &= ~SFLAG_CLIENT;
6083 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6084 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6085 surface->Flags |= SFLAG_NONPOW2;
6086 } else {
6087 surface->Flags &= ~SFLAG_NONPOW2;
6089 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6090 surface->resource.allocatedMemory = NULL;
6091 surface->resource.heapMemory = NULL;
6092 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6094 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6095 * to a FBO */
6096 if (!surface_init_sysmem(surface))
6098 return E_OUTOFMEMORY;
6100 return WINED3D_OK;
6103 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6104 TRACE("Unloading resource %p\n", resource);
6105 IWineD3DResource_UnLoad(resource);
6106 IWineD3DResource_Release(resource);
6107 return S_OK;
6110 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6112 UINT i, count;
6113 WINED3DDISPLAYMODE m;
6114 HRESULT hr;
6116 /* All Windowed modes are supported, as is leaving the current mode */
6117 if(pp->Windowed) return TRUE;
6118 if(!pp->BackBufferWidth) return TRUE;
6119 if(!pp->BackBufferHeight) return TRUE;
6121 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6122 for(i = 0; i < count; i++) {
6123 memset(&m, 0, sizeof(m));
6124 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6125 if(FAILED(hr)) {
6126 ERR("EnumAdapterModes failed\n");
6128 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6129 /* Mode found, it is supported */
6130 return TRUE;
6133 /* Mode not found -> not supported */
6134 return FALSE;
6137 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6140 const struct wined3d_gl_info *gl_info;
6141 struct wined3d_context *context;
6142 IWineD3DBaseShaderImpl *shader;
6144 context = context_acquire(This, NULL);
6145 gl_info = context->gl_info;
6147 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6148 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6149 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6152 ENTER_GL();
6153 if(This->depth_blt_texture) {
6154 glDeleteTextures(1, &This->depth_blt_texture);
6155 This->depth_blt_texture = 0;
6157 if (This->depth_blt_rb) {
6158 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6159 This->depth_blt_rb = 0;
6160 This->depth_blt_rb_w = 0;
6161 This->depth_blt_rb_h = 0;
6163 LEAVE_GL();
6165 This->blitter->free_private(iface);
6166 This->frag_pipe->free_private(iface);
6167 This->shader_backend->shader_free_private(iface);
6168 destroy_dummy_textures(This, gl_info);
6170 context_release(context);
6172 while (This->numContexts)
6174 context_destroy(This, This->contexts[0]);
6176 HeapFree(GetProcessHeap(), 0, swapchain->context);
6177 swapchain->context = NULL;
6178 swapchain->num_contexts = 0;
6181 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6184 struct wined3d_context *context;
6185 HRESULT hr;
6186 IWineD3DSurfaceImpl *target;
6188 /* Recreate the primary swapchain's context */
6189 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6190 if (!swapchain->context)
6192 ERR("Failed to allocate memory for swapchain context array.\n");
6193 return E_OUTOFMEMORY;
6196 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6197 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6199 WARN("Failed to create context.\n");
6200 HeapFree(GetProcessHeap(), 0, swapchain->context);
6201 return E_FAIL;
6204 swapchain->context[0] = context;
6205 swapchain->num_contexts = 1;
6206 create_dummy_textures(This);
6207 context_release(context);
6209 hr = This->shader_backend->shader_alloc_private(iface);
6210 if (FAILED(hr))
6212 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6213 goto err;
6216 hr = This->frag_pipe->alloc_private(iface);
6217 if (FAILED(hr))
6219 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6220 This->shader_backend->shader_free_private(iface);
6221 goto err;
6224 hr = This->blitter->alloc_private(iface);
6225 if (FAILED(hr))
6227 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6228 This->frag_pipe->free_private(iface);
6229 This->shader_backend->shader_free_private(iface);
6230 goto err;
6233 return WINED3D_OK;
6235 err:
6236 context_acquire(This, NULL);
6237 destroy_dummy_textures(This, context->gl_info);
6238 context_release(context);
6239 context_destroy(This, context);
6240 HeapFree(GetProcessHeap(), 0, swapchain->context);
6241 swapchain->num_contexts = 0;
6242 return hr;
6245 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6247 IWineD3DSwapChainImpl *swapchain;
6248 HRESULT hr;
6249 BOOL DisplayModeChanged = FALSE;
6250 WINED3DDISPLAYMODE mode;
6251 TRACE("(%p)\n", This);
6253 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6254 if(FAILED(hr)) {
6255 ERR("Failed to get the first implicit swapchain\n");
6256 return hr;
6259 if(!is_display_mode_supported(This, pPresentationParameters)) {
6260 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6261 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6262 pPresentationParameters->BackBufferHeight);
6263 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6264 return WINED3DERR_INVALIDCALL;
6267 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6268 * on an existing gl context, so there's no real need for recreation.
6270 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6272 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6274 TRACE("New params:\n");
6275 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6276 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6277 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6278 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6279 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6280 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6281 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6282 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6283 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6284 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6285 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6286 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6287 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6289 /* No special treatment of these parameters. Just store them */
6290 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6291 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6292 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6293 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6295 /* What to do about these? */
6296 if(pPresentationParameters->BackBufferCount != 0 &&
6297 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6298 ERR("Cannot change the back buffer count yet\n");
6300 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6301 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6302 ERR("Cannot change the back buffer format yet\n");
6304 if(pPresentationParameters->hDeviceWindow != NULL &&
6305 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6306 ERR("Cannot change the device window yet\n");
6308 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6310 HRESULT hrc;
6312 TRACE("Creating the depth stencil buffer\n");
6314 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6315 This->parent,
6316 pPresentationParameters->BackBufferWidth,
6317 pPresentationParameters->BackBufferHeight,
6318 pPresentationParameters->AutoDepthStencilFormat,
6319 pPresentationParameters->MultiSampleType,
6320 pPresentationParameters->MultiSampleQuality,
6321 FALSE,
6322 (IWineD3DSurface **)&This->auto_depth_stencil);
6324 if (FAILED(hrc)) {
6325 ERR("Failed to create the depth stencil buffer\n");
6326 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6327 return WINED3DERR_INVALIDCALL;
6331 if (This->onscreen_depth_stencil)
6333 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6334 This->onscreen_depth_stencil = NULL;
6337 /* Reset the depth stencil */
6338 if (pPresentationParameters->EnableAutoDepthStencil)
6339 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6340 else
6341 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6343 TRACE("Resetting stateblock\n");
6344 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6345 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6347 delete_opengl_contexts(iface, swapchain);
6349 if(pPresentationParameters->Windowed) {
6350 mode.Width = swapchain->orig_width;
6351 mode.Height = swapchain->orig_height;
6352 mode.RefreshRate = 0;
6353 mode.Format = swapchain->presentParms.BackBufferFormat;
6354 } else {
6355 mode.Width = pPresentationParameters->BackBufferWidth;
6356 mode.Height = pPresentationParameters->BackBufferHeight;
6357 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6358 mode.Format = swapchain->presentParms.BackBufferFormat;
6361 /* Should Width == 800 && Height == 0 set 800x600? */
6362 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6363 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6364 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6366 UINT i;
6368 if(!pPresentationParameters->Windowed) {
6369 DisplayModeChanged = TRUE;
6371 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6372 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6374 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6375 if(FAILED(hr))
6377 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6378 return hr;
6381 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6383 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6384 if(FAILED(hr))
6386 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6387 return hr;
6390 if (This->auto_depth_stencil)
6392 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6393 if(FAILED(hr))
6395 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6396 return hr;
6401 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6402 || DisplayModeChanged)
6404 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6406 if (!pPresentationParameters->Windowed)
6408 if(swapchain->presentParms.Windowed) {
6409 /* switch from windowed to fs */
6410 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6411 pPresentationParameters->BackBufferHeight);
6412 } else {
6413 /* Fullscreen -> fullscreen mode change */
6414 MoveWindow(swapchain->device_window, 0, 0,
6415 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6416 TRUE);
6419 else if (!swapchain->presentParms.Windowed)
6421 /* Fullscreen -> windowed switch */
6422 swapchain_restore_fullscreen_window(swapchain);
6424 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6425 } else if(!pPresentationParameters->Windowed) {
6426 DWORD style = This->style, exStyle = This->exStyle;
6427 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6428 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6429 * Reset to clear up their mess. Guild Wars also loses the device during that.
6431 This->style = 0;
6432 This->exStyle = 0;
6433 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6434 pPresentationParameters->BackBufferHeight);
6435 This->style = style;
6436 This->exStyle = exStyle;
6439 /* Note: No parent needed for initial internal stateblock */
6440 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6441 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6442 else TRACE("Created stateblock %p\n", This->stateBlock);
6443 This->updateStateBlock = This->stateBlock;
6444 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6446 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6447 if(FAILED(hr)) {
6448 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6451 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6453 RECT client_rect;
6454 GetClientRect(swapchain->win_handle, &client_rect);
6456 if(!swapchain->presentParms.BackBufferCount)
6458 TRACE("Single buffered rendering\n");
6459 swapchain->render_to_fbo = FALSE;
6461 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6462 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6464 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6465 swapchain->presentParms.BackBufferWidth,
6466 swapchain->presentParms.BackBufferHeight,
6467 client_rect.right, client_rect.bottom);
6468 swapchain->render_to_fbo = TRUE;
6470 else
6472 TRACE("Rendering directly to GL_BACK\n");
6473 swapchain->render_to_fbo = FALSE;
6477 hr = create_primary_opengl_context(iface, swapchain);
6478 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6480 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6481 * first use
6483 return hr;
6486 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6488 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6490 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6492 return WINED3D_OK;
6496 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6498 TRACE("(%p) : pParameters %p\n", This, pParameters);
6500 *pParameters = This->createParms;
6501 return WINED3D_OK;
6504 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6505 IWineD3DSwapChain *swapchain;
6507 TRACE("Relaying to swapchain\n");
6509 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6510 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6511 IWineD3DSwapChain_Release(swapchain);
6515 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6516 IWineD3DSwapChain *swapchain;
6518 TRACE("Relaying to swapchain\n");
6520 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6521 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6522 IWineD3DSwapChain_Release(swapchain);
6527 /** ********************************************************
6528 * Notification functions
6529 ** ********************************************************/
6530 /** This function must be called in the release of a resource when ref == 0,
6531 * the contents of resource must still be correct,
6532 * any handles to other resource held by the caller must be closed
6533 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6534 *****************************************************/
6535 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6537 TRACE("(%p) : Adding resource %p\n", This, resource);
6539 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6542 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6544 TRACE("(%p) : Removing resource %p\n", This, resource);
6546 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6549 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6551 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6552 int counter;
6554 TRACE("(%p) : resource %p\n", This, resource);
6556 context_resource_released(This, resource, type);
6558 switch (type) {
6559 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6560 case WINED3DRTYPE_SURFACE: {
6561 unsigned int i;
6563 if (This->d3d_initialized)
6565 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6567 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6568 This->render_targets[i] = NULL;
6570 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6571 This->depth_stencil = NULL;
6574 break;
6576 case WINED3DRTYPE_TEXTURE:
6577 case WINED3DRTYPE_CUBETEXTURE:
6578 case WINED3DRTYPE_VOLUMETEXTURE:
6579 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6580 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6581 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6582 This->stateBlock->textures[counter] = NULL;
6584 if (This->updateStateBlock != This->stateBlock ){
6585 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6586 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6587 This->updateStateBlock->textures[counter] = NULL;
6591 break;
6592 case WINED3DRTYPE_VOLUME:
6593 /* TODO: nothing really? */
6594 break;
6595 case WINED3DRTYPE_BUFFER:
6597 int streamNumber;
6598 TRACE("Cleaning up stream pointers\n");
6600 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6601 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6602 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6604 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6605 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6606 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6607 This->updateStateBlock->streamSource[streamNumber] = 0;
6608 /* Set changed flag? */
6611 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6612 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6613 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6614 This->stateBlock->streamSource[streamNumber] = 0;
6619 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6620 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6621 This->updateStateBlock->pIndexData = NULL;
6624 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6625 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6626 This->stateBlock->pIndexData = NULL;
6630 break;
6632 default:
6633 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6634 break;
6638 /* Remove the resource from the resourceStore */
6639 device_resource_remove(This, resource);
6641 TRACE("Resource released\n");
6645 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6647 IWineD3DResourceImpl *resource, *cursor;
6648 HRESULT ret;
6649 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6651 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6652 TRACE("enumerating resource %p\n", resource);
6653 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6654 ret = pCallback((IWineD3DResource *) resource, pData);
6655 if(ret == S_FALSE) {
6656 TRACE("Canceling enumeration\n");
6657 break;
6660 return WINED3D_OK;
6663 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6666 IWineD3DResourceImpl *resource;
6668 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6670 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6671 if (type == WINED3DRTYPE_SURFACE)
6673 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6675 TRACE("Found surface %p for dc %p.\n", resource, dc);
6676 *surface = (IWineD3DSurface *)resource;
6677 return WINED3D_OK;
6682 return WINED3DERR_INVALIDCALL;
6685 /**********************************************************
6686 * IWineD3DDevice VTbl follows
6687 **********************************************************/
6689 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6691 /*** IUnknown methods ***/
6692 IWineD3DDeviceImpl_QueryInterface,
6693 IWineD3DDeviceImpl_AddRef,
6694 IWineD3DDeviceImpl_Release,
6695 /*** IWineD3DDevice methods ***/
6696 IWineD3DDeviceImpl_GetParent,
6697 /*** Creation methods**/
6698 IWineD3DDeviceImpl_CreateBuffer,
6699 IWineD3DDeviceImpl_CreateVertexBuffer,
6700 IWineD3DDeviceImpl_CreateIndexBuffer,
6701 IWineD3DDeviceImpl_CreateStateBlock,
6702 IWineD3DDeviceImpl_CreateSurface,
6703 IWineD3DDeviceImpl_CreateRendertargetView,
6704 IWineD3DDeviceImpl_CreateTexture,
6705 IWineD3DDeviceImpl_CreateVolumeTexture,
6706 IWineD3DDeviceImpl_CreateVolume,
6707 IWineD3DDeviceImpl_CreateCubeTexture,
6708 IWineD3DDeviceImpl_CreateQuery,
6709 IWineD3DDeviceImpl_CreateSwapChain,
6710 IWineD3DDeviceImpl_CreateVertexDeclaration,
6711 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6712 IWineD3DDeviceImpl_CreateVertexShader,
6713 IWineD3DDeviceImpl_CreateGeometryShader,
6714 IWineD3DDeviceImpl_CreatePixelShader,
6715 IWineD3DDeviceImpl_CreatePalette,
6716 /*** Odd functions **/
6717 IWineD3DDeviceImpl_Init3D,
6718 IWineD3DDeviceImpl_InitGDI,
6719 IWineD3DDeviceImpl_Uninit3D,
6720 IWineD3DDeviceImpl_UninitGDI,
6721 IWineD3DDeviceImpl_SetMultithreaded,
6722 IWineD3DDeviceImpl_EvictManagedResources,
6723 IWineD3DDeviceImpl_GetAvailableTextureMem,
6724 IWineD3DDeviceImpl_GetBackBuffer,
6725 IWineD3DDeviceImpl_GetCreationParameters,
6726 IWineD3DDeviceImpl_GetDeviceCaps,
6727 IWineD3DDeviceImpl_GetDirect3D,
6728 IWineD3DDeviceImpl_GetDisplayMode,
6729 IWineD3DDeviceImpl_SetDisplayMode,
6730 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6731 IWineD3DDeviceImpl_GetRasterStatus,
6732 IWineD3DDeviceImpl_GetSwapChain,
6733 IWineD3DDeviceImpl_Reset,
6734 IWineD3DDeviceImpl_SetDialogBoxMode,
6735 IWineD3DDeviceImpl_SetCursorProperties,
6736 IWineD3DDeviceImpl_SetCursorPosition,
6737 IWineD3DDeviceImpl_ShowCursor,
6738 /*** Getters and setters **/
6739 IWineD3DDeviceImpl_SetClipPlane,
6740 IWineD3DDeviceImpl_GetClipPlane,
6741 IWineD3DDeviceImpl_SetClipStatus,
6742 IWineD3DDeviceImpl_GetClipStatus,
6743 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6744 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6745 IWineD3DDeviceImpl_SetDepthStencilSurface,
6746 IWineD3DDeviceImpl_GetDepthStencilSurface,
6747 IWineD3DDeviceImpl_SetGammaRamp,
6748 IWineD3DDeviceImpl_GetGammaRamp,
6749 IWineD3DDeviceImpl_SetIndexBuffer,
6750 IWineD3DDeviceImpl_GetIndexBuffer,
6751 IWineD3DDeviceImpl_SetBaseVertexIndex,
6752 IWineD3DDeviceImpl_GetBaseVertexIndex,
6753 IWineD3DDeviceImpl_SetLight,
6754 IWineD3DDeviceImpl_GetLight,
6755 IWineD3DDeviceImpl_SetLightEnable,
6756 IWineD3DDeviceImpl_GetLightEnable,
6757 IWineD3DDeviceImpl_SetMaterial,
6758 IWineD3DDeviceImpl_GetMaterial,
6759 IWineD3DDeviceImpl_SetNPatchMode,
6760 IWineD3DDeviceImpl_GetNPatchMode,
6761 IWineD3DDeviceImpl_SetPaletteEntries,
6762 IWineD3DDeviceImpl_GetPaletteEntries,
6763 IWineD3DDeviceImpl_SetPixelShader,
6764 IWineD3DDeviceImpl_GetPixelShader,
6765 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6766 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6767 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6768 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6769 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6770 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6771 IWineD3DDeviceImpl_SetRenderState,
6772 IWineD3DDeviceImpl_GetRenderState,
6773 IWineD3DDeviceImpl_SetRenderTarget,
6774 IWineD3DDeviceImpl_GetRenderTarget,
6775 IWineD3DDeviceImpl_SetFrontBackBuffers,
6776 IWineD3DDeviceImpl_SetSamplerState,
6777 IWineD3DDeviceImpl_GetSamplerState,
6778 IWineD3DDeviceImpl_SetScissorRect,
6779 IWineD3DDeviceImpl_GetScissorRect,
6780 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6781 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6782 IWineD3DDeviceImpl_SetStreamSource,
6783 IWineD3DDeviceImpl_GetStreamSource,
6784 IWineD3DDeviceImpl_SetStreamSourceFreq,
6785 IWineD3DDeviceImpl_GetStreamSourceFreq,
6786 IWineD3DDeviceImpl_SetTexture,
6787 IWineD3DDeviceImpl_GetTexture,
6788 IWineD3DDeviceImpl_SetTextureStageState,
6789 IWineD3DDeviceImpl_GetTextureStageState,
6790 IWineD3DDeviceImpl_SetTransform,
6791 IWineD3DDeviceImpl_GetTransform,
6792 IWineD3DDeviceImpl_SetVertexDeclaration,
6793 IWineD3DDeviceImpl_GetVertexDeclaration,
6794 IWineD3DDeviceImpl_SetVertexShader,
6795 IWineD3DDeviceImpl_GetVertexShader,
6796 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6797 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6798 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6799 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6800 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6801 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6802 IWineD3DDeviceImpl_SetViewport,
6803 IWineD3DDeviceImpl_GetViewport,
6804 IWineD3DDeviceImpl_MultiplyTransform,
6805 IWineD3DDeviceImpl_ValidateDevice,
6806 IWineD3DDeviceImpl_ProcessVertices,
6807 /*** State block ***/
6808 IWineD3DDeviceImpl_BeginStateBlock,
6809 IWineD3DDeviceImpl_EndStateBlock,
6810 /*** Scene management ***/
6811 IWineD3DDeviceImpl_BeginScene,
6812 IWineD3DDeviceImpl_EndScene,
6813 IWineD3DDeviceImpl_Present,
6814 IWineD3DDeviceImpl_Clear,
6815 IWineD3DDeviceImpl_ClearRendertargetView,
6816 /*** Drawing ***/
6817 IWineD3DDeviceImpl_SetPrimitiveType,
6818 IWineD3DDeviceImpl_GetPrimitiveType,
6819 IWineD3DDeviceImpl_DrawPrimitive,
6820 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6821 IWineD3DDeviceImpl_DrawPrimitiveUP,
6822 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6823 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6824 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6825 IWineD3DDeviceImpl_DrawRectPatch,
6826 IWineD3DDeviceImpl_DrawTriPatch,
6827 IWineD3DDeviceImpl_DeletePatch,
6828 IWineD3DDeviceImpl_ColorFill,
6829 IWineD3DDeviceImpl_UpdateTexture,
6830 IWineD3DDeviceImpl_UpdateSurface,
6831 IWineD3DDeviceImpl_GetFrontBufferData,
6832 /*** object tracking ***/
6833 IWineD3DDeviceImpl_EnumResources,
6834 IWineD3DDeviceImpl_GetSurfaceFromDC,
6835 IWineD3DDeviceImpl_AcquireFocusWindow,
6836 IWineD3DDeviceImpl_ReleaseFocusWindow,
6839 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6840 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6841 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6843 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6844 const struct fragment_pipeline *fragment_pipeline;
6845 struct shader_caps shader_caps;
6846 struct fragment_caps ffp_caps;
6847 WINED3DDISPLAYMODE mode;
6848 unsigned int i;
6849 HRESULT hr;
6851 device->lpVtbl = &IWineD3DDevice_Vtbl;
6852 device->ref = 1;
6853 device->wined3d = (IWineD3D *)wined3d;
6854 IWineD3D_AddRef(device->wined3d);
6855 device->adapter = wined3d->adapter_count ? adapter : NULL;
6856 device->parent = parent;
6857 device->device_parent = device_parent;
6858 list_init(&device->resources);
6859 list_init(&device->shaders);
6861 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6862 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6864 /* Get the initial screen setup for ddraw. */
6865 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6866 if (FAILED(hr))
6868 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6869 IWineD3D_Release(device->wined3d);
6870 return hr;
6872 device->ddraw_width = mode.Width;
6873 device->ddraw_height = mode.Height;
6874 device->ddraw_format = mode.Format;
6876 /* Save the creation parameters. */
6877 device->createParms.AdapterOrdinal = adapter_idx;
6878 device->createParms.DeviceType = device_type;
6879 device->createParms.hFocusWindow = focus_window;
6880 device->createParms.BehaviorFlags = flags;
6882 device->devType = device_type;
6883 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6885 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6886 device->shader_backend = adapter->shader_backend;
6888 if (device->shader_backend)
6890 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6891 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6892 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6893 device->vs_clipping = shader_caps.VSClipping;
6895 fragment_pipeline = adapter->fragment_pipe;
6896 device->frag_pipe = fragment_pipeline;
6897 if (fragment_pipeline)
6899 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6900 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6902 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6903 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6904 if (FAILED(hr))
6906 ERR("Failed to compile state table, hr %#x.\n", hr);
6907 IWineD3D_Release(device->wined3d);
6908 return hr;
6911 device->blitter = adapter->blitter;
6913 return WINED3D_OK;
6917 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6918 DWORD rep = This->StateTable[state].representative;
6919 struct wined3d_context *context;
6920 DWORD idx;
6921 BYTE shift;
6922 UINT i;
6924 for(i = 0; i < This->numContexts; i++) {
6925 context = This->contexts[i];
6926 if(isStateDirty(context, rep)) continue;
6928 context->dirtyArray[context->numDirtyEntries++] = rep;
6929 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6930 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6931 context->isStateDirty[idx] |= (1 << shift);
6935 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6937 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6938 *width = context->current_rt->pow2Width;
6939 *height = context->current_rt->pow2Height;
6942 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6944 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6945 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6946 * current context's drawable, which is the size of the back buffer of the swapchain
6947 * the active context belongs to. */
6948 *width = swapchain->presentParms.BackBufferWidth;
6949 *height = swapchain->presentParms.BackBufferHeight;
6952 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6953 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6955 if (device->filter_messages)
6957 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6958 window, message, wparam, lparam);
6959 return DefWindowProcW(window, message, wparam, lparam);
6962 if (message == WM_DESTROY)
6964 TRACE("unregister window %p.\n", window);
6965 wined3d_unregister_window(window);
6967 if (device->focus_window == window) device->focus_window = NULL;
6968 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6971 return CallWindowProcW(proc, window, message, wparam, lparam);