wined3d: Move the material to wined3d_state.
[wine/testsucceed.git] / dlls / wined3d / device.c
blobab7e2ed9be7a9c518298622c1842adf6817e71ac
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && !usage_idx)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && !usage_idx)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && !usage_idx)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && !usage_idx)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && !usage_idx)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (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 struct wined3d_buffer *buffer = This->stateBlock->streams[element->input_slot].buffer;
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!buffer) continue;
206 stride = This->stateBlock->streams[element->input_slot].stride;
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, buffer);
210 buffer_object = 0;
211 data = (BYTE *)buffer;
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, buffer);
216 data = buffer_get_memory((IWineD3DBuffer *)buffer, &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
226 buffer_object = 0;
227 data = buffer_get_sysmem(buffer, &This->adapter->gl_info);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
234 if (fixup)
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format->id), buffer_object);
293 stream_info->elements[idx].format = element->format;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
319 if (!(map & 1)) continue;
321 element = &stream_info->elements[i];
322 buffer = This->stateBlock->streams[element->stream_idx].buffer;
323 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
325 /* If PreLoad dropped the buffer object, update the stream info. */
326 if (buffer->buffer_object != element->buffer_object)
328 element->buffer_object = 0;
329 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
332 if (buffer->query)
333 This->buffer_queries[This->num_buffer_queries++] = buffer->query;
338 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
339 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
341 e->format = wined3d_get_format(gl_info, strided->format);
342 e->stride = strided->dwStride;
343 e->data = strided->lpData;
344 e->stream_idx = 0;
345 e->buffer_object = 0;
348 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
349 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
351 unsigned int i;
353 memset(stream_info, 0, sizeof(*stream_info));
355 if (strided->position.lpData)
356 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
357 if (strided->normal.lpData)
358 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
359 if (strided->diffuse.lpData)
360 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
361 if (strided->specular.lpData)
362 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
364 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
366 if (strided->texCoords[i].lpData)
367 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
368 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
371 stream_info->position_transformed = strided->position_transformed;
373 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
375 if (!stream_info->elements[i].format) continue;
377 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
378 && stream_info->elements[i].format->id == WINED3DFMT_B8G8R8A8_UNORM)
380 stream_info->swizzle_map |= 1 << i;
382 stream_info->use_map |= 1 << i;
386 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
388 TRACE("Strided Data:\n");
389 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
406 /* Context activation is done by the caller. */
407 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
409 struct wined3d_stream_info *stream_info = &device->strided_streams;
410 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
411 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
412 BOOL fixup = FALSE;
414 if (device->up_strided)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
419 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
421 else
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
427 if (vs && !stream_info->position_transformed)
429 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device->useDrawStridedSlow = TRUE;
434 else
436 device->useDrawStridedSlow = FALSE;
439 else
441 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
442 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
443 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
445 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
447 device->useDrawStridedSlow = TRUE;
449 else
451 device->useDrawStridedSlow = FALSE;
456 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
458 IWineD3DBaseTextureImpl *texture;
459 enum WINED3DSRGB srgb;
461 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
462 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
463 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
466 void device_preload_textures(IWineD3DDeviceImpl *device)
468 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
469 unsigned int i;
471 if (use_vs(stateblock))
473 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
475 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
476 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
480 if (use_ps(stateblock))
482 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
484 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
485 device_preload_texture(stateblock, i);
488 else
490 WORD ffu_map = device->fixed_function_usage_map;
492 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
494 if (ffu_map & 1)
495 device_preload_texture(stateblock, i);
500 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
502 struct wined3d_context **new_array;
504 TRACE("Adding context %p.\n", context);
506 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
507 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
509 if (!new_array)
511 ERR("Failed to grow the context array.\n");
512 return FALSE;
515 new_array[device->numContexts++] = context;
516 device->contexts = new_array;
517 return TRUE;
520 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
522 struct wined3d_context **new_array;
523 BOOL found = FALSE;
524 UINT i;
526 TRACE("Removing context %p.\n", context);
528 for (i = 0; i < device->numContexts; ++i)
530 if (device->contexts[i] == context)
532 found = TRUE;
533 break;
537 if (!found)
539 ERR("Context %p doesn't exist in context array.\n", context);
540 return;
543 if (!--device->numContexts)
545 HeapFree(GetProcessHeap(), 0, device->contexts);
546 device->contexts = NULL;
547 return;
550 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
551 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
552 if (!new_array)
554 ERR("Failed to shrink context array. Oh well.\n");
555 return;
558 device->contexts = new_array;
561 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
563 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
564 WINED3DVIEWPORT *vp = &stateblock->state.viewport;
566 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
568 if (stateblock->state.render_states[WINED3DRS_SCISSORTESTENABLE])
570 IntersectRect(rect, rect, &stateblock->state.scissor_rect);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
576 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
578 if (device->onscreen_depth_stencil)
580 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
581 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
582 device->onscreen_depth_stencil->ds_current_size.cx,
583 device->onscreen_depth_stencil->ds_current_size.cy);
584 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
586 device->onscreen_depth_stencil = depth_stencil;
587 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
590 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
592 /* partial draw rect */
593 if (draw_rect->left || draw_rect->top
594 || draw_rect->right < target->currentDesc.Width
595 || draw_rect->bottom < target->currentDesc.Height)
596 return FALSE;
598 /* partial clear rect */
599 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
600 || clear_rect->right < target->currentDesc.Width
601 || clear_rect->bottom < target->currentDesc.Height))
602 return FALSE;
604 return TRUE;
607 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
608 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
610 RECT current_rect, r;
612 if (ds->Flags & location)
613 SetRect(&current_rect, 0, 0,
614 ds->ds_current_size.cx,
615 ds->ds_current_size.cy);
616 else
617 SetRectEmpty(&current_rect);
619 IntersectRect(&r, draw_rect, &current_rect);
620 if (EqualRect(&r, draw_rect))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
624 return;
627 if (EqualRect(&r, &current_rect))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
631 if (!clear_rect)
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
635 return;
638 IntersectRect(&r, draw_rect, clear_rect);
639 if (EqualRect(&r, draw_rect))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 return;
647 /* Full load. */
648 surface_load_ds_location(ds, context, location);
649 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
652 /* Do not call while under the GL lock. */
653 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
654 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
655 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
657 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
658 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
659 IWineD3DSurfaceImpl *target = rts[0];
660 UINT drawable_width, drawable_height;
661 struct wined3d_context *context;
662 GLbitfield clear_mask = 0;
663 unsigned int i;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
675 for (i = 0; i < rt_count; ++i)
677 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
681 context = context_acquire(device, target);
682 if (!context->valid)
684 context_release(context);
685 WARN("Invalid context, skipping clear.\n");
686 return WINED3D_OK;
689 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
691 target->get_drawable_size(context, &drawable_width, &drawable_height);
693 ENTER_GL();
695 /* Only set the values up once, as they are not changing. */
696 if (flags & WINED3DCLEAR_STENCIL)
698 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
700 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
701 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
703 glStencilMask(~0U);
704 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
705 glClearStencil(stencil);
706 checkGLcall("glClearStencil");
707 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
710 if (flags & WINED3DCLEAR_ZBUFFER)
712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
714 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
716 LEAVE_GL();
717 device_switch_onscreen_ds(device, context, depth_stencil);
718 ENTER_GL();
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
725 glClearDepth(depth);
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
747 if (!clear_rect)
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
754 else
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
760 glClear(clear_mask);
761 checkGLcall("glClear");
763 else
765 RECT current_rect;
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(&current_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(&current_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
783 continue;
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
791 else
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
798 glClear(clear_mask);
799 checkGLcall("glClear");
803 LEAVE_GL();
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
811 return WINED3D_OK;
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface, REFIID riid, void **object)
821 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
823 if (IsEqualGUID(riid, &IID_IWineD3DDevice)
824 || IsEqualGUID(riid, &IID_IUnknown))
826 IUnknown_AddRef(iface);
827 *object = iface;
828 return S_OK;
831 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
833 *object = NULL;
834 return E_NOINTERFACE;
837 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
839 ULONG refCount = InterlockedIncrement(&This->ref);
841 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
842 return refCount;
845 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 ULONG refCount = InterlockedDecrement(&This->ref);
849 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
851 if (!refCount) {
852 UINT i;
854 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
855 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
856 This->multistate_funcs[i] = NULL;
859 /* TODO: Clean up all the surfaces and textures! */
860 /* NOTE: You must release the parent if the object was created via a callback
861 ** ***************************/
863 if (!list_empty(&This->resources))
865 IWineD3DResourceImpl *resource;
866 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
868 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
870 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
871 FIXME("Leftover resource %p with type %s (%#x).\n",
872 resource, debug_d3dresourcetype(type), type);
876 if(This->contexts) ERR("Context array not freed!\n");
877 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
878 This->haveHardwareCursor = FALSE;
880 IWineD3D_Release(This->wined3d);
881 This->wined3d = NULL;
882 HeapFree(GetProcessHeap(), 0, This);
883 TRACE("Freed device %p\n", This);
884 This = NULL;
886 return refCount;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
890 const void *data, void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 struct wined3d_buffer *object;
894 HRESULT hr;
896 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Failed to allocate memory\n");
902 return E_OUTOFMEMORY;
905 FIXME("Ignoring access flags (pool)\n");
907 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
908 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
909 if (FAILED(hr))
911 WARN("Failed to initialize buffer, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 return hr;
915 object->desc = *desc;
917 TRACE("Created buffer %p.\n", object);
919 *buffer = (IWineD3DBuffer *)object;
921 return WINED3D_OK;
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
925 UINT Size, DWORD Usage, WINED3DPOOL Pool, void *parent,
926 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppVertexBuffer)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 struct wined3d_buffer *object;
930 HRESULT hr;
932 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
933 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
935 if (Pool == WINED3DPOOL_SCRATCH)
937 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
938 * anyway, SCRATCH vertex buffers aren't usable anywhere
940 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
941 *ppVertexBuffer = NULL;
942 return WINED3DERR_INVALIDCALL;
945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
946 if (!object)
948 ERR("Out of memory\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_OUTOFVIDEOMEMORY;
953 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
954 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
955 if (FAILED(hr))
957 WARN("Failed to initialize buffer, hr %#x.\n", hr);
958 HeapFree(GetProcessHeap(), 0, object);
959 return hr;
962 TRACE("Created buffer %p.\n", object);
963 *ppVertexBuffer = (IWineD3DBuffer *)object;
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
969 UINT Length, DWORD Usage, WINED3DPOOL Pool, void *parent,
970 const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **ppIndexBuffer)
972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
973 struct wined3d_buffer *object;
974 HRESULT hr;
976 TRACE("(%p) Creating index buffer\n", This);
978 /* Allocate the storage for the device */
979 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
980 if (!object)
982 ERR("Out of memory\n");
983 *ppIndexBuffer = NULL;
984 return WINED3DERR_OUTOFVIDEOMEMORY;
987 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
988 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
989 parent, parent_ops);
990 if (FAILED(hr))
992 WARN("Failed to initialize buffer, hr %#x\n", hr);
993 HeapFree(GetProcessHeap(), 0, object);
994 return hr;
997 TRACE("Created buffer %p.\n", object);
999 *ppIndexBuffer = (IWineD3DBuffer *) object;
1001 return WINED3D_OK;
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1005 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DStateBlockImpl *object;
1009 HRESULT hr;
1011 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1012 if(!object)
1014 ERR("Failed to allocate stateblock memory.\n");
1015 return E_OUTOFMEMORY;
1018 hr = stateblock_init(object, This, type);
1019 if (FAILED(hr))
1021 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1022 HeapFree(GetProcessHeap(), 0, object);
1023 return hr;
1026 TRACE("Created stateblock %p.\n", object);
1027 *stateblock = (IWineD3DStateBlock *)object;
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1033 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, DWORD Usage, WINED3DPOOL Pool,
1034 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl,
1035 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSurface **surface)
1037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1038 IWineD3DSurfaceImpl *object;
1039 HRESULT hr;
1041 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1042 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1043 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1044 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1045 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1047 if (Impl == SURFACE_OPENGL && !This->adapter)
1049 ERR("OpenGL surfaces are not available without OpenGL.\n");
1050 return WINED3DERR_NOTAVAILABLE;
1053 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054 if (!object)
1056 ERR("Failed to allocate surface memory.\n");
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1061 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1062 if (FAILED(hr))
1064 WARN("Failed to initialize surface, returning %#x.\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1066 return hr;
1069 TRACE("(%p) : Created surface %p\n", This, object);
1071 *surface = (IWineD3DSurface *)object;
1073 return hr;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1077 IWineD3DResource *resource, void *parent, IWineD3DRendertargetView **rendertarget_view)
1079 struct wined3d_rendertarget_view *object;
1081 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1082 iface, resource, parent, rendertarget_view);
1084 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1085 if (!object)
1087 ERR("Failed to allocate memory\n");
1088 return E_OUTOFMEMORY;
1091 wined3d_rendertarget_view_init(object, resource, parent);
1093 TRACE("Created render target view %p.\n", object);
1094 *rendertarget_view = (IWineD3DRendertargetView *)object;
1096 return WINED3D_OK;
1099 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1100 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1101 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DTexture **ppTexture)
1103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1104 IWineD3DTextureImpl *object;
1105 HRESULT hr;
1107 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1108 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1109 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1112 if (!object)
1114 ERR("Out of memory\n");
1115 *ppTexture = NULL;
1116 return WINED3DERR_OUTOFVIDEOMEMORY;
1119 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1120 if (FAILED(hr))
1122 WARN("Failed to initialize texture, returning %#x\n", hr);
1123 HeapFree(GetProcessHeap(), 0, object);
1124 *ppTexture = NULL;
1125 return hr;
1128 *ppTexture = (IWineD3DTexture *)object;
1130 TRACE("(%p) : Created texture %p\n", This, object);
1132 return WINED3D_OK;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1136 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1137 void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DVolumeTexture **ppVolumeTexture)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVolumeTextureImpl *object;
1141 HRESULT hr;
1143 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1144 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1146 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1147 if (!object)
1149 ERR("Out of memory\n");
1150 *ppVolumeTexture = NULL;
1151 return WINED3DERR_OUTOFVIDEOMEMORY;
1154 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1155 if (FAILED(hr))
1157 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1158 HeapFree(GetProcessHeap(), 0, object);
1159 *ppVolumeTexture = NULL;
1160 return hr;
1163 TRACE("(%p) : Created volume texture %p.\n", This, object);
1164 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1166 return WINED3D_OK;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1170 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1171 const struct wined3d_parent_ops *parent_ops, IWineD3DVolume **ppVolume)
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DVolumeImpl *object;
1175 HRESULT hr;
1177 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1178 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1180 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1181 if (!object)
1183 ERR("Out of memory\n");
1184 *ppVolume = NULL;
1185 return WINED3DERR_OUTOFVIDEOMEMORY;
1188 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1189 if (FAILED(hr))
1191 WARN("Failed to initialize volume, returning %#x.\n", hr);
1192 HeapFree(GetProcessHeap(), 0, object);
1193 return hr;
1196 TRACE("(%p) : Created volume %p.\n", This, object);
1197 *ppVolume = (IWineD3DVolume *)object;
1199 return WINED3D_OK;
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1203 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, void *parent,
1204 const struct wined3d_parent_ops *parent_ops, IWineD3DCubeTexture **ppCubeTexture)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1208 HRESULT hr;
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1211 if (!object)
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1219 if (FAILED(hr))
1221 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1222 HeapFree(GetProcessHeap(), 0, object);
1223 *ppCubeTexture = NULL;
1224 return hr;
1227 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1228 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1230 return WINED3D_OK;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1234 WINED3DQUERYTYPE type, IWineD3DQuery **query)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DQueryImpl *object;
1238 HRESULT hr;
1240 TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
1242 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1243 if (!object)
1245 ERR("Failed to allocate query memory.\n");
1246 return E_OUTOFMEMORY;
1249 hr = query_init(object, This, type);
1250 if (FAILED(hr))
1252 WARN("Failed to initialize query, hr %#x.\n", hr);
1253 HeapFree(GetProcessHeap(), 0, object);
1254 return hr;
1257 TRACE("Created query %p.\n", object);
1258 *query = (IWineD3DQuery *)object;
1260 return WINED3D_OK;
1263 /* Do not call while under the GL lock. */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1265 WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
1266 void *parent, IWineD3DSwapChain **swapchain)
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 IWineD3DSwapChainImpl *object;
1270 HRESULT hr;
1272 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1273 iface, present_parameters, swapchain, parent, surface_type);
1275 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1276 if (!object)
1278 ERR("Failed to allocate swapchain memory.\n");
1279 return E_OUTOFMEMORY;
1282 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1283 if (FAILED(hr))
1285 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1286 HeapFree(GetProcessHeap(), 0, object);
1287 return hr;
1290 TRACE("Created swapchain %p.\n", object);
1291 *swapchain = (IWineD3DSwapChain *)object;
1293 return WINED3D_OK;
1296 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1297 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 TRACE("(%p)\n", This);
1301 return This->NumberOfSwapChains;
1304 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1308 if(iSwapChain < This->NumberOfSwapChains) {
1309 *pSwapChain = This->swapchains[iSwapChain];
1310 IWineD3DSwapChain_AddRef(*pSwapChain);
1311 TRACE("(%p) returning %p\n", This, *pSwapChain);
1312 return WINED3D_OK;
1313 } else {
1314 TRACE("Swapchain out of range\n");
1315 *pSwapChain = NULL;
1316 return WINED3DERR_INVALIDCALL;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1321 const WINED3DVERTEXELEMENT *elements, UINT element_count, void *parent,
1322 const struct wined3d_parent_ops *parent_ops, IWineD3DVertexDeclaration **declaration)
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 IWineD3DVertexDeclarationImpl *object = NULL;
1326 HRESULT hr;
1328 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1329 iface, declaration, parent, elements, element_count);
1331 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1332 if(!object)
1334 ERR("Failed to allocate vertex declaration memory.\n");
1335 return E_OUTOFMEMORY;
1338 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1339 if (FAILED(hr))
1341 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1342 HeapFree(GetProcessHeap(), 0, object);
1343 return hr;
1346 TRACE("Created vertex declaration %p.\n", object);
1347 *declaration = (IWineD3DVertexDeclaration *)object;
1349 return WINED3D_OK;
1352 struct wined3d_fvf_convert_state
1354 const struct wined3d_gl_info *gl_info;
1355 WINED3DVERTEXELEMENT *elements;
1356 UINT offset;
1357 UINT idx;
1360 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1361 enum wined3d_format_id format_id, WINED3DDECLUSAGE usage, UINT usage_idx)
1363 WINED3DVERTEXELEMENT *elements = state->elements;
1364 const struct wined3d_format *format;
1365 UINT offset = state->offset;
1366 UINT idx = state->idx;
1368 elements[idx].format = format_id;
1369 elements[idx].input_slot = 0;
1370 elements[idx].offset = offset;
1371 elements[idx].output_slot = 0;
1372 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1373 elements[idx].usage = usage;
1374 elements[idx].usage_idx = usage_idx;
1376 format = wined3d_get_format(state->gl_info, format_id);
1377 state->offset += format->component_count * format->component_size;
1378 ++state->idx;
1381 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1382 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1385 BOOL has_pos = !!(fvf & WINED3DFVF_POSITION_MASK);
1386 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1387 BOOL has_blend_idx = has_blend &&
1388 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1389 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1390 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1391 BOOL has_normal = !!(fvf & WINED3DFVF_NORMAL);
1392 BOOL has_psize = !!(fvf & WINED3DFVF_PSIZE);
1393 BOOL has_diffuse = !!(fvf & WINED3DFVF_DIFFUSE);
1394 BOOL has_specular = !!(fvf & WINED3DFVF_SPECULAR);
1396 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1397 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1398 struct wined3d_fvf_convert_state state;
1399 unsigned int size;
1400 unsigned int idx;
1401 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1402 if (has_blend_idx) num_blends--;
1404 /* Compute declaration size */
1405 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1406 has_psize + has_diffuse + has_specular + num_textures;
1408 state.gl_info = gl_info;
1409 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1410 if (!state.elements) return ~0U;
1411 state.offset = 0;
1412 state.idx = 0;
1414 if (has_pos)
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1417 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1418 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1419 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1420 else
1421 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1424 if (has_blend && (num_blends > 0))
1426 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1427 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1428 else
1430 switch (num_blends)
1432 case 1:
1433 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1434 break;
1435 case 2:
1436 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1437 break;
1438 case 3:
1439 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 break;
1441 case 4:
1442 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 break;
1444 default:
1445 ERR("Unexpected amount of blend values: %u\n", num_blends);
1450 if (has_blend_idx)
1452 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1453 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1454 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1455 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1456 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1457 else
1458 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1461 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1462 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1463 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1464 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1466 for (idx = 0; idx < num_textures; ++idx)
1468 switch ((texcoords >> (idx * 2)) & 0x03)
1470 case WINED3DFVF_TEXTUREFORMAT1:
1471 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1472 break;
1473 case WINED3DFVF_TEXTUREFORMAT2:
1474 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1475 break;
1476 case WINED3DFVF_TEXTUREFORMAT3:
1477 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1478 break;
1479 case WINED3DFVF_TEXTUREFORMAT4:
1480 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1481 break;
1485 *ppVertexElements = state.elements;
1486 return size;
1489 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1490 DWORD fvf, void *parent, const struct wined3d_parent_ops *parent_ops,
1491 IWineD3DVertexDeclaration **declaration)
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1494 WINED3DVERTEXELEMENT *elements;
1495 unsigned int size;
1496 DWORD hr;
1498 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1500 size = ConvertFvfToDeclaration(This, fvf, &elements);
1501 if (size == ~0U) return E_OUTOFMEMORY;
1503 hr = IWineD3DDeviceImpl_CreateVertexDeclaration(iface, elements, size, parent, parent_ops, declaration);
1504 HeapFree(GetProcessHeap(), 0, elements);
1505 return hr;
1508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1509 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1510 void *parent, const struct wined3d_parent_ops *parent_ops,
1511 IWineD3DVertexShader **ppVertexShader)
1513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1514 IWineD3DVertexShaderImpl *object;
1515 HRESULT hr;
1517 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1518 if (!object)
1520 ERR("Failed to allocate shader memory.\n");
1521 return E_OUTOFMEMORY;
1524 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1525 if (FAILED(hr))
1527 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1528 HeapFree(GetProcessHeap(), 0, object);
1529 return hr;
1532 TRACE("Created vertex shader %p.\n", object);
1533 *ppVertexShader = (IWineD3DVertexShader *)object;
1535 return WINED3D_OK;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1539 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1540 void *parent, const struct wined3d_parent_ops *parent_ops,
1541 IWineD3DGeometryShader **shader)
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 struct wined3d_geometryshader *object;
1545 HRESULT hr;
1547 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1548 if (!object)
1550 ERR("Failed to allocate shader memory.\n");
1551 return E_OUTOFMEMORY;
1554 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1555 if (FAILED(hr))
1557 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1558 HeapFree(GetProcessHeap(), 0, object);
1559 return hr;
1562 TRACE("Created geometry shader %p.\n", object);
1563 *shader = (IWineD3DGeometryShader *)object;
1565 return WINED3D_OK;
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1569 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1570 void *parent, const struct wined3d_parent_ops *parent_ops,
1571 IWineD3DPixelShader **ppPixelShader)
1573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1574 IWineD3DPixelShaderImpl *object;
1575 HRESULT hr;
1577 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1578 if (!object)
1580 ERR("Failed to allocate shader memory.\n");
1581 return E_OUTOFMEMORY;
1584 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1585 if (FAILED(hr))
1587 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1588 HeapFree(GetProcessHeap(), 0, object);
1589 return hr;
1592 TRACE("Created pixel shader %p.\n", object);
1593 *ppPixelShader = (IWineD3DPixelShader *)object;
1595 return WINED3D_OK;
1598 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1599 const PALETTEENTRY *PalEnt, void *parent, IWineD3DPalette **Palette)
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1602 IWineD3DPaletteImpl *object;
1603 HRESULT hr;
1605 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1606 iface, Flags, PalEnt, Palette, parent);
1608 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1609 if (!object)
1611 ERR("Failed to allocate palette memory.\n");
1612 return E_OUTOFMEMORY;
1615 hr = wined3d_palette_init(object, This, Flags, PalEnt, parent);
1616 if (FAILED(hr))
1618 WARN("Failed to initialize palette, hr %#x.\n", hr);
1619 HeapFree(GetProcessHeap(), 0, object);
1620 return hr;
1623 TRACE("Created palette %p.\n", object);
1624 *Palette = (IWineD3DPalette *)object;
1626 return WINED3D_OK;
1629 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1630 HBITMAP hbm;
1631 BITMAP bm;
1632 HRESULT hr;
1633 HDC dcb = NULL, dcs = NULL;
1634 WINEDDCOLORKEY colorkey;
1636 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1637 if(hbm)
1639 GetObjectA(hbm, sizeof(BITMAP), &bm);
1640 dcb = CreateCompatibleDC(NULL);
1641 if(!dcb) goto out;
1642 SelectObject(dcb, hbm);
1644 else
1646 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1647 * couldn't be loaded
1649 memset(&bm, 0, sizeof(bm));
1650 bm.bmWidth = 32;
1651 bm.bmHeight = 32;
1654 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1655 FALSE, 0, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL,
1656 &wined3d_null_parent_ops, &This->logo_surface);
1657 if (FAILED(hr))
1659 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
1660 goto out;
1663 if(dcb) {
1664 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1665 if(FAILED(hr)) goto out;
1666 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1667 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1669 colorkey.dwColorSpaceLowValue = 0;
1670 colorkey.dwColorSpaceHighValue = 0;
1671 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1673 else
1675 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1676 /* Fill the surface with a white color to show that wined3d is there */
1677 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1680 out:
1681 if (dcb) DeleteDC(dcb);
1682 if (hbm) DeleteObject(hbm);
1685 /* Context activation is done by the caller. */
1686 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1688 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1689 unsigned int i;
1690 /* Under DirectX you can have texture stage operations even if no texture is
1691 bound, whereas opengl will only do texture operations when a valid texture is
1692 bound. We emulate this by creating dummy textures and binding them to each
1693 texture stage, but disable all stages by default. Hence if a stage is enabled
1694 then the default texture will kick in until replaced by a SetTexture call */
1695 ENTER_GL();
1697 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1699 /* The dummy texture does not have client storage backing */
1700 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1701 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1704 for (i = 0; i < gl_info->limits.textures; ++i)
1706 GLubyte white = 255;
1708 /* Make appropriate texture active */
1709 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1710 checkGLcall("glActiveTextureARB");
1712 /* Generate an opengl texture name */
1713 glGenTextures(1, &This->dummyTextureName[i]);
1714 checkGLcall("glGenTextures");
1715 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1717 /* Generate a dummy 2d texture (not using 1d because they cause many
1718 * DRI drivers fall back to sw) */
1719 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1720 checkGLcall("glBindTexture");
1722 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1723 checkGLcall("glTexImage2D");
1726 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1728 /* Reenable because if supported it is enabled by default */
1729 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1730 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1733 LEAVE_GL();
1736 /* Context activation is done by the caller. */
1737 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1739 ENTER_GL();
1740 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1741 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1742 LEAVE_GL();
1744 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1747 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1749 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1751 if (!wined3d_register_window(window, device))
1753 ERR("Failed to register window %p.\n", window);
1754 return E_FAIL;
1757 device->focus_window = window;
1758 SetForegroundWindow(window);
1760 return WINED3D_OK;
1763 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1765 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1767 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1768 device->focus_window = NULL;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1772 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1776 IWineD3DSwapChainImpl *swapchain = NULL;
1777 struct wined3d_context *context;
1778 HRESULT hr;
1779 DWORD state;
1780 unsigned int i;
1782 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1784 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1785 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1787 TRACE("(%p) : Creating stateblock\n", This);
1788 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1789 if (FAILED(hr))
1791 WARN("Failed to create stateblock\n");
1792 goto err_out;
1794 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1795 This->updateStateBlock = This->stateBlock;
1796 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1798 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1799 sizeof(*This->render_targets) * gl_info->limits.buffers);
1801 This->NumberOfPalettes = 1;
1802 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1803 if (!This->palettes || !This->render_targets)
1805 ERR("Out of memory!\n");
1806 hr = E_OUTOFMEMORY;
1807 goto err_out;
1809 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1810 if(!This->palettes[0]) {
1811 ERR("Out of memory!\n");
1812 hr = E_OUTOFMEMORY;
1813 goto err_out;
1815 for (i = 0; i < 256; ++i) {
1816 This->palettes[0][i].peRed = 0xFF;
1817 This->palettes[0][i].peGreen = 0xFF;
1818 This->palettes[0][i].peBlue = 0xFF;
1819 This->palettes[0][i].peFlags = 0xFF;
1821 This->currentPalette = 0;
1823 /* Initialize the texture unit mapping to a 1:1 mapping */
1824 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1826 if (state < gl_info->limits.fragment_samplers)
1828 This->texUnitMap[state] = state;
1829 This->rev_tex_unit_map[state] = state;
1830 } else {
1831 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1832 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1836 /* Setup the implicit swapchain. This also initializes a context. */
1837 TRACE("Creating implicit swapchain\n");
1838 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1839 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1840 if (FAILED(hr))
1842 WARN("Failed to create implicit swapchain\n");
1843 goto err_out;
1846 This->NumberOfSwapChains = 1;
1847 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1848 if(!This->swapchains) {
1849 ERR("Out of memory!\n");
1850 goto err_out;
1852 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1854 if (swapchain->back_buffers && swapchain->back_buffers[0])
1856 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1857 This->render_targets[0] = swapchain->back_buffers[0];
1859 else
1861 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1862 This->render_targets[0] = swapchain->front_buffer;
1864 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1866 /* Depth Stencil support */
1867 This->depth_stencil = This->auto_depth_stencil;
1868 if (This->depth_stencil)
1869 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1871 hr = This->shader_backend->shader_alloc_private(iface);
1872 if(FAILED(hr)) {
1873 TRACE("Shader private data couldn't be allocated\n");
1874 goto err_out;
1876 hr = This->frag_pipe->alloc_private(iface);
1877 if(FAILED(hr)) {
1878 TRACE("Fragment pipeline private data couldn't be allocated\n");
1879 goto err_out;
1881 hr = This->blitter->alloc_private(iface);
1882 if(FAILED(hr)) {
1883 TRACE("Blitter private data couldn't be allocated\n");
1884 goto err_out;
1887 /* Set up some starting GL setup */
1889 /* Setup all the devices defaults */
1890 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1892 context = context_acquire(This, swapchain->front_buffer);
1894 create_dummy_textures(This);
1896 ENTER_GL();
1898 /* Initialize the current view state */
1899 This->view_ident = 1;
1900 This->contexts[0]->last_was_rhw = 0;
1901 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1902 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1904 switch(wined3d_settings.offscreen_rendering_mode) {
1905 case ORM_FBO:
1906 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1907 break;
1909 case ORM_BACKBUFFER:
1911 if (context_get_current()->aux_buffers > 0)
1913 TRACE("Using auxilliary buffer for offscreen rendering\n");
1914 This->offscreenBuffer = GL_AUX0;
1915 } else {
1916 TRACE("Using back buffer for offscreen rendering\n");
1917 This->offscreenBuffer = GL_BACK;
1922 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1923 LEAVE_GL();
1925 context_release(context);
1927 /* Clear the screen */
1928 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1929 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1930 0x00, 1.0f, 0);
1932 This->d3d_initialized = TRUE;
1934 if(wined3d_settings.logo) {
1935 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1937 This->highest_dirty_ps_const = 0;
1938 This->highest_dirty_vs_const = 0;
1939 return WINED3D_OK;
1941 err_out:
1942 HeapFree(GetProcessHeap(), 0, This->render_targets);
1943 HeapFree(GetProcessHeap(), 0, This->swapchains);
1944 This->NumberOfSwapChains = 0;
1945 if(This->palettes) {
1946 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1947 HeapFree(GetProcessHeap(), 0, This->palettes);
1949 This->NumberOfPalettes = 0;
1950 if(swapchain) {
1951 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1953 if(This->stateBlock) {
1954 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1955 This->stateBlock = NULL;
1957 if (This->blit_priv) {
1958 This->blitter->free_private(iface);
1960 if (This->fragment_priv) {
1961 This->frag_pipe->free_private(iface);
1963 if (This->shader_priv) {
1964 This->shader_backend->shader_free_private(iface);
1966 return hr;
1969 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1970 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1973 IWineD3DSwapChainImpl *swapchain = NULL;
1974 HRESULT hr;
1976 /* Setup the implicit swapchain */
1977 TRACE("Creating implicit swapchain\n");
1978 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1979 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1980 if (FAILED(hr))
1982 WARN("Failed to create implicit swapchain\n");
1983 goto err_out;
1986 This->NumberOfSwapChains = 1;
1987 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1988 if(!This->swapchains) {
1989 ERR("Out of memory!\n");
1990 goto err_out;
1992 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1993 return WINED3D_OK;
1995 err_out:
1996 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1997 return hr;
2000 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2002 IWineD3DResource_UnLoad(resource);
2003 IWineD3DResource_Release(resource);
2004 return WINED3D_OK;
2007 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2008 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2011 const struct wined3d_gl_info *gl_info;
2012 struct wined3d_context *context;
2013 int sampler;
2014 UINT i;
2015 TRACE("(%p)\n", This);
2017 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2019 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2020 * it was created. Thus make sure a context is active for the glDelete* calls
2022 context = context_acquire(This, NULL);
2023 gl_info = context->gl_info;
2025 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2027 /* Unload resources */
2028 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2030 TRACE("Deleting high order patches\n");
2031 for(i = 0; i < PATCHMAP_SIZE; i++) {
2032 struct list *e1, *e2;
2033 struct WineD3DRectPatch *patch;
2034 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2035 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2036 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2040 /* Delete the mouse cursor texture */
2041 if(This->cursorTexture) {
2042 ENTER_GL();
2043 glDeleteTextures(1, &This->cursorTexture);
2044 LEAVE_GL();
2045 This->cursorTexture = 0;
2048 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2049 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2051 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2052 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2055 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2056 * private data, it might contain opengl pointers
2058 if(This->depth_blt_texture) {
2059 ENTER_GL();
2060 glDeleteTextures(1, &This->depth_blt_texture);
2061 LEAVE_GL();
2062 This->depth_blt_texture = 0;
2064 if (This->depth_blt_rb) {
2065 ENTER_GL();
2066 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2067 LEAVE_GL();
2068 This->depth_blt_rb = 0;
2069 This->depth_blt_rb_w = 0;
2070 This->depth_blt_rb_h = 0;
2073 /* Release the update stateblock */
2074 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2075 if(This->updateStateBlock != This->stateBlock)
2076 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2078 This->updateStateBlock = NULL;
2080 { /* because were not doing proper internal refcounts releasing the primary state block
2081 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2082 to set this->stateBlock = NULL; first */
2083 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2084 This->stateBlock = NULL;
2086 /* Release the stateblock */
2087 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2088 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2092 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2093 This->blitter->free_private(iface);
2094 This->frag_pipe->free_private(iface);
2095 This->shader_backend->shader_free_private(iface);
2097 /* Release the buffers (with sanity checks)*/
2098 if (This->onscreen_depth_stencil)
2100 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2101 This->onscreen_depth_stencil = NULL;
2104 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2105 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2107 if (This->auto_depth_stencil != This->depth_stencil)
2108 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2110 This->depth_stencil = NULL;
2112 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2113 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2115 TRACE("Setting rendertarget to NULL\n");
2116 This->render_targets[0] = NULL;
2118 if (This->auto_depth_stencil)
2120 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2122 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2124 This->auto_depth_stencil = NULL;
2127 context_release(context);
2129 for(i=0; i < This->NumberOfSwapChains; i++) {
2130 TRACE("Releasing the implicit swapchain %d\n", i);
2131 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2132 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2136 HeapFree(GetProcessHeap(), 0, This->swapchains);
2137 This->swapchains = NULL;
2138 This->NumberOfSwapChains = 0;
2140 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2141 HeapFree(GetProcessHeap(), 0, This->palettes);
2142 This->palettes = NULL;
2143 This->NumberOfPalettes = 0;
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 This->render_targets = NULL;
2148 This->d3d_initialized = FALSE;
2150 return WINED3D_OK;
2153 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2155 unsigned int i;
2157 for(i=0; i < This->NumberOfSwapChains; i++) {
2158 TRACE("Releasing the implicit swapchain %d\n", i);
2159 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2160 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2164 HeapFree(GetProcessHeap(), 0, This->swapchains);
2165 This->swapchains = NULL;
2166 This->NumberOfSwapChains = 0;
2167 return WINED3D_OK;
2170 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2171 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2172 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2174 * There is no way to deactivate thread safety once it is enabled.
2176 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2179 /*For now just store the flag(needed in case of ddraw) */
2180 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2183 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2184 const WINED3DDISPLAYMODE* pMode) {
2185 DEVMODEW devmode;
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 const struct wined3d_format *format = wined3d_get_format(&This->adapter->gl_info, pMode->Format);
2188 LONG ret;
2189 RECT clip_rc;
2191 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2193 /* Resize the screen even without a window:
2194 * The app could have unset it with SetCooperativeLevel, but not called
2195 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2196 * but we don't have any hwnd
2199 memset(&devmode, 0, sizeof(devmode));
2200 devmode.dmSize = sizeof(devmode);
2201 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2202 devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
2203 devmode.dmPelsWidth = pMode->Width;
2204 devmode.dmPelsHeight = pMode->Height;
2206 devmode.dmDisplayFrequency = pMode->RefreshRate;
2207 if (pMode->RefreshRate)
2208 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2210 /* Only change the mode if necessary */
2211 if (This->ddraw_width == pMode->Width && This->ddraw_height == pMode->Height
2212 && This->ddraw_format == pMode->Format && !pMode->RefreshRate)
2213 return WINED3D_OK;
2215 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2216 if (ret != DISP_CHANGE_SUCCESSFUL)
2218 if (devmode.dmDisplayFrequency)
2220 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2221 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2222 devmode.dmDisplayFrequency = 0;
2223 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2225 if(ret != DISP_CHANGE_SUCCESSFUL) {
2226 return WINED3DERR_NOTAVAILABLE;
2230 /* Store the new values */
2231 This->ddraw_width = pMode->Width;
2232 This->ddraw_height = pMode->Height;
2233 This->ddraw_format = pMode->Format;
2235 /* And finally clip mouse to our screen */
2236 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2237 ClipCursor(&clip_rc);
2239 return WINED3D_OK;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 *ppD3D = This->wined3d;
2245 TRACE("Returning %p.\n", *ppD3D);
2246 IWineD3D_AddRef(*ppD3D);
2247 return WINED3D_OK;
2250 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2254 (This->adapter->TextureRam/(1024*1024)),
2255 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2256 /* return simulated texture memory left */
2257 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2260 /*****
2261 * Get / Set Stream Source
2262 *****/
2263 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2264 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2267 struct wined3d_stream_state *stream;
2268 IWineD3DBuffer *oldSrc;
2270 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2271 iface, StreamNumber, pStreamData, OffsetInBytes, Stride);
2273 if (StreamNumber >= MAX_STREAMS) {
2274 WARN("Stream out of range %d\n", StreamNumber);
2275 return WINED3DERR_INVALIDCALL;
2276 } else if(OffsetInBytes & 0x3) {
2277 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2278 return WINED3DERR_INVALIDCALL;
2281 stream = &This->updateStateBlock->streams[StreamNumber];
2282 oldSrc = (IWineD3DBuffer *)stream->buffer;
2284 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2286 if (oldSrc == pStreamData
2287 && stream->stride == Stride
2288 && stream->offset == OffsetInBytes)
2290 TRACE("Application is setting the old values over, nothing to do\n");
2291 return WINED3D_OK;
2294 stream->buffer = (struct wined3d_buffer *)pStreamData;
2295 if (pStreamData)
2297 stream->stride = Stride;
2298 stream->offset = OffsetInBytes;
2301 /* Handle recording of state blocks */
2302 if (This->isRecordingState) {
2303 TRACE("Recording... not performing anything\n");
2304 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2305 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2306 return WINED3D_OK;
2309 if (pStreamData)
2311 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2312 IWineD3DBuffer_AddRef(pStreamData);
2314 if (oldSrc)
2316 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2317 IWineD3DBuffer_Release(oldSrc);
2320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2322 return WINED3D_OK;
2325 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2326 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 struct wined3d_stream_state *stream;
2331 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2332 iface, StreamNumber, pStream, pOffset, pStride);
2334 if (StreamNumber >= MAX_STREAMS)
2336 WARN("Stream out of range %d\n", StreamNumber);
2337 return WINED3DERR_INVALIDCALL;
2340 stream = &This->stateBlock->streams[StreamNumber];
2341 *pStream = (IWineD3DBuffer *)stream->buffer;
2342 *pStride = stream->stride;
2343 if (pOffset) *pOffset = stream->offset;
2345 if (*pStream) IWineD3DBuffer_AddRef(*pStream);
2347 return WINED3D_OK;
2350 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 struct wined3d_stream_state *stream;
2353 UINT oldFlags, oldFreq;
2355 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface, StreamNumber, Divider);
2357 /* Verify input at least in d3d9 this is invalid. */
2358 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
2360 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2361 return WINED3DERR_INVALIDCALL;
2363 if ((Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !StreamNumber)
2365 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2368 if (!Divider)
2370 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2374 stream = &This->updateStateBlock->streams[StreamNumber];
2375 oldFlags = stream->flags;
2376 oldFreq = stream->frequency;
2378 stream->flags = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
2379 stream->frequency = Divider & 0x7FFFFF;
2381 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2383 if (stream->frequency != oldFreq || stream->flags != oldFlags)
2384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2386 return WINED3D_OK;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 struct wined3d_stream_state *stream;
2393 TRACE("iface %p, stream_idx %u, divider %p.\n", iface, StreamNumber, Divider);
2395 stream = &This->updateStateBlock->streams[StreamNumber];
2396 *Divider = stream->flags | stream->frequency;
2398 TRACE("Returning %#x.\n", *Divider);
2400 return WINED3D_OK;
2403 /*****
2404 * Get / Set & Multiply Transform
2405 *****/
2406 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 /* Most of this routine, comments included copied from ddraw tree initially: */
2410 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2412 /* Handle recording of state blocks */
2413 if (This->isRecordingState) {
2414 TRACE("Recording... not performing anything\n");
2415 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2416 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2417 return WINED3D_OK;
2421 * If the new matrix is the same as the current one,
2422 * we cut off any further processing. this seems to be a reasonable
2423 * optimization because as was noticed, some apps (warcraft3 for example)
2424 * tend towards setting the same matrix repeatedly for some reason.
2426 * From here on we assume that the new matrix is different, wherever it matters.
2428 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2429 TRACE("The app is setting the same matrix over again\n");
2430 return WINED3D_OK;
2431 } else {
2432 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2436 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2437 where ViewMat = Camera space, WorldMat = world space.
2439 In OpenGL, camera and world space is combined into GL_MODELVIEW
2440 matrix. The Projection matrix stay projection matrix.
2443 /* Capture the times we can just ignore the change for now */
2444 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2445 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2446 /* Handled by the state manager */
2449 if (d3dts < WINED3DTS_WORLDMATRIX(This->adapter->gl_info.limits.blends))
2450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2452 return WINED3D_OK;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2458 *pMatrix = This->stateBlock->transforms[State];
2459 return WINED3D_OK;
2462 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2463 const WINED3DMATRIX *mat = NULL;
2464 WINED3DMATRIX temp;
2466 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2467 * below means it will be recorded in a state block change, but it
2468 * works regardless where it is recorded.
2469 * If this is found to be wrong, change to StateBlock.
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2474 if (State <= HIGHEST_TRANSFORMSTATE)
2476 mat = &This->updateStateBlock->transforms[State];
2477 } else {
2478 FIXME("Unhandled transform state!!\n");
2481 multiply_matrix(&temp, mat, pMatrix);
2483 /* Apply change via set transform - will reapply to eg. lights this way */
2484 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2487 /*****
2488 * Get / Set Light
2489 *****/
2490 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2491 you can reference any indexes you want as long as that number max are enabled at any
2492 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2493 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2494 but when recording, just build a chain pretty much of commands to be replayed. */
2496 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2497 float rho;
2498 struct wined3d_light_info *object = NULL;
2499 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2500 struct list *e;
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2505 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2506 * the gl driver.
2508 if(!pLight) {
2509 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2510 return WINED3DERR_INVALIDCALL;
2513 switch(pLight->Type) {
2514 case WINED3DLIGHT_POINT:
2515 case WINED3DLIGHT_SPOT:
2516 case WINED3DLIGHT_PARALLELPOINT:
2517 case WINED3DLIGHT_GLSPOT:
2518 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2519 * most wanted
2521 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2523 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2524 return WINED3DERR_INVALIDCALL;
2526 break;
2528 case WINED3DLIGHT_DIRECTIONAL:
2529 /* Ignores attenuation */
2530 break;
2532 default:
2533 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2534 return WINED3DERR_INVALIDCALL;
2537 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2539 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2540 if(object->OriginalIndex == Index) break;
2541 object = NULL;
2544 if(!object) {
2545 TRACE("Adding new light\n");
2546 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2547 if(!object) {
2548 ERR("Out of memory error when allocating a light\n");
2549 return E_OUTOFMEMORY;
2551 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2552 object->glIndex = -1;
2553 object->OriginalIndex = Index;
2556 /* Initialize the object */
2557 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,
2558 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2559 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2560 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2561 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2562 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2563 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2565 /* Save away the information */
2566 object->OriginalParms = *pLight;
2568 switch (pLight->Type) {
2569 case WINED3DLIGHT_POINT:
2570 /* Position */
2571 object->lightPosn[0] = pLight->Position.x;
2572 object->lightPosn[1] = pLight->Position.y;
2573 object->lightPosn[2] = pLight->Position.z;
2574 object->lightPosn[3] = 1.0f;
2575 object->cutoff = 180.0f;
2576 /* FIXME: Range */
2577 break;
2579 case WINED3DLIGHT_DIRECTIONAL:
2580 /* Direction */
2581 object->lightPosn[0] = -pLight->Direction.x;
2582 object->lightPosn[1] = -pLight->Direction.y;
2583 object->lightPosn[2] = -pLight->Direction.z;
2584 object->lightPosn[3] = 0.0f;
2585 object->exponent = 0.0f;
2586 object->cutoff = 180.0f;
2587 break;
2589 case WINED3DLIGHT_SPOT:
2590 /* Position */
2591 object->lightPosn[0] = pLight->Position.x;
2592 object->lightPosn[1] = pLight->Position.y;
2593 object->lightPosn[2] = pLight->Position.z;
2594 object->lightPosn[3] = 1.0f;
2596 /* Direction */
2597 object->lightDirn[0] = pLight->Direction.x;
2598 object->lightDirn[1] = pLight->Direction.y;
2599 object->lightDirn[2] = pLight->Direction.z;
2600 object->lightDirn[3] = 1.0f;
2603 * opengl-ish and d3d-ish spot lights use too different models for the
2604 * light "intensity" as a function of the angle towards the main light direction,
2605 * so we only can approximate very roughly.
2606 * however spot lights are rather rarely used in games (if ever used at all).
2607 * furthermore if still used, probably nobody pays attention to such details.
2609 if (!pLight->Falloff)
2611 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2612 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2613 * will always be 1.0 for both of them, and we don't have to care for the
2614 * rest of the rather complex calculation
2616 object->exponent = 0.0f;
2617 } else {
2618 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2619 if (rho < 0.0001f) rho = 0.0001f;
2620 object->exponent = -0.3f/logf(cosf(rho/2));
2622 if (object->exponent > 128.0f)
2624 object->exponent = 128.0f;
2626 object->cutoff = (float) (pLight->Phi*90/M_PI);
2628 /* FIXME: Range */
2629 break;
2631 default:
2632 FIXME("Unrecognized light type %d\n", pLight->Type);
2635 /* Update the live definitions if the light is currently assigned a glIndex */
2636 if (object->glIndex != -1 && !This->isRecordingState) {
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2644 struct wined3d_light_info *lightInfo = NULL;
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2647 struct list *e;
2648 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2650 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2652 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2653 if(lightInfo->OriginalIndex == Index) break;
2654 lightInfo = NULL;
2657 if (!lightInfo)
2659 TRACE("Light information requested but light not defined\n");
2660 return WINED3DERR_INVALIDCALL;
2663 *pLight = lightInfo->OriginalParms;
2664 return WINED3D_OK;
2667 /*****
2668 * Get / Set Light Enable
2669 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2670 *****/
2671 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2673 struct wined3d_light_info *lightInfo = NULL;
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2676 struct list *e;
2677 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2679 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2681 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2682 if(lightInfo->OriginalIndex == Index) break;
2683 lightInfo = NULL;
2685 TRACE("Found light: %p\n", lightInfo);
2687 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2688 if (!lightInfo)
2690 TRACE("Light enabled requested but light not defined, so defining one!\n");
2691 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2693 /* Search for it again! Should be fairly quick as near head of list */
2694 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2696 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2697 if(lightInfo->OriginalIndex == Index) break;
2698 lightInfo = NULL;
2700 if (!lightInfo)
2702 FIXME("Adding default lights has failed dismally\n");
2703 return WINED3DERR_INVALIDCALL;
2707 if(!Enable) {
2708 if(lightInfo->glIndex != -1) {
2709 if(!This->isRecordingState) {
2710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2713 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2714 lightInfo->glIndex = -1;
2715 } else {
2716 TRACE("Light already disabled, nothing to do\n");
2718 lightInfo->enabled = FALSE;
2719 } else {
2720 lightInfo->enabled = TRUE;
2721 if (lightInfo->glIndex != -1) {
2722 /* nop */
2723 TRACE("Nothing to do as light was enabled\n");
2724 } else {
2725 int i;
2726 /* Find a free gl light */
2727 for (i = 0; i < This->maxConcurrentLights; ++i)
2729 if (!This->updateStateBlock->activeLights[i])
2731 This->updateStateBlock->activeLights[i] = lightInfo;
2732 lightInfo->glIndex = i;
2733 break;
2736 if(lightInfo->glIndex == -1) {
2737 /* Our tests show that Windows returns D3D_OK in this situation, even with
2738 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2739 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2740 * as well for those lights.
2742 * TODO: Test how this affects rendering
2744 WARN("Too many concurrently active lights\n");
2745 return WINED3D_OK;
2748 /* i == lightInfo->glIndex */
2749 if(!This->isRecordingState) {
2750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2755 return WINED3D_OK;
2758 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2760 struct wined3d_light_info *lightInfo = NULL;
2761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2762 struct list *e;
2763 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2764 TRACE("(%p) : for idx(%d)\n", This, Index);
2766 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2768 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2769 if(lightInfo->OriginalIndex == Index) break;
2770 lightInfo = NULL;
2773 if (!lightInfo)
2775 TRACE("Light enabled state requested but light not defined\n");
2776 return WINED3DERR_INVALIDCALL;
2778 /* true is 128 according to SetLightEnable */
2779 *pEnable = lightInfo->enabled ? 128 : 0;
2780 return WINED3D_OK;
2783 /*****
2784 * Get / Set Clip Planes
2785 *****/
2786 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2790 /* Validate Index */
2791 if (Index >= This->adapter->gl_info.limits.clipplanes)
2793 TRACE("Application has requested clipplane this device doesn't support\n");
2794 return WINED3DERR_INVALIDCALL;
2797 This->updateStateBlock->changed.clipplane |= 1 << Index;
2799 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2800 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2801 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2802 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2803 TRACE("Application is setting old values over, nothing to do\n");
2804 return WINED3D_OK;
2807 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2808 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2809 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2810 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2812 /* Handle recording of state blocks */
2813 if (This->isRecordingState) {
2814 TRACE("Recording... not performing anything\n");
2815 return WINED3D_OK;
2818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2820 return WINED3D_OK;
2823 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2825 TRACE("(%p) : for idx %d\n", This, Index);
2827 /* Validate Index */
2828 if (Index >= This->adapter->gl_info.limits.clipplanes)
2830 TRACE("Application has requested clipplane this device doesn't support\n");
2831 return WINED3DERR_INVALIDCALL;
2834 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2835 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2836 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2837 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2838 return WINED3D_OK;
2841 /*****
2842 * Get / Set Clip Plane Status
2843 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2844 *****/
2845 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2847 FIXME("(%p) : stub\n", This);
2849 if (!pClipStatus)
2850 return WINED3DERR_INVALIDCALL;
2852 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2853 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2854 return WINED3D_OK;
2857 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 FIXME("(%p) : stub\n", This);
2861 if (!pClipStatus)
2862 return WINED3DERR_INVALIDCALL;
2864 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2865 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2866 return WINED3D_OK;
2869 /*****
2870 * Get / Set Material
2871 *****/
2872 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 This->updateStateBlock->changed.material = TRUE;
2876 This->updateStateBlock->state.material = *pMaterial;
2878 /* Handle recording of state blocks */
2879 if (This->isRecordingState) {
2880 TRACE("Recording... not performing anything\n");
2881 return WINED3D_OK;
2884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 *pMaterial = This->updateStateBlock->state.material;
2891 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2892 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2893 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2894 pMaterial->Ambient.b, pMaterial->Ambient.a);
2895 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2896 pMaterial->Specular.b, pMaterial->Specular.a);
2897 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2898 pMaterial->Emissive.b, pMaterial->Emissive.a);
2899 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2901 return WINED3D_OK;
2904 /*****
2905 * Get / Set Indices
2906 *****/
2907 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2908 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2911 IWineD3DBuffer *oldIdxs;
2913 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2914 oldIdxs = This->updateStateBlock->pIndexData;
2916 This->updateStateBlock->changed.indices = TRUE;
2917 This->updateStateBlock->pIndexData = pIndexData;
2918 This->updateStateBlock->IndexFmt = fmt;
2920 /* Handle recording of state blocks */
2921 if (This->isRecordingState) {
2922 TRACE("Recording... not performing anything\n");
2923 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2924 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2925 return WINED3D_OK;
2928 if(oldIdxs != pIndexData) {
2929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2930 if(pIndexData) {
2931 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2932 IWineD3DBuffer_AddRef(pIndexData);
2934 if(oldIdxs) {
2935 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2936 IWineD3DBuffer_Release(oldIdxs);
2940 return WINED3D_OK;
2943 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 *ppIndexData = This->stateBlock->pIndexData;
2949 /* up ref count on ppindexdata */
2950 if (*ppIndexData) {
2951 IWineD3DBuffer_AddRef(*ppIndexData);
2952 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2953 }else{
2954 TRACE("(%p) No index data set\n", This);
2956 TRACE("Returning %p\n", *ppIndexData);
2958 return WINED3D_OK;
2961 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p)->(%d)\n", This, BaseIndex);
2966 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2967 TRACE("Application is setting the old value over, nothing to do\n");
2968 return WINED3D_OK;
2971 This->updateStateBlock->baseVertexIndex = BaseIndex;
2973 if (This->isRecordingState) {
2974 TRACE("Recording... not performing anything\n");
2975 return WINED3D_OK;
2977 /* The base vertex index affects the stream sources */
2978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2979 return WINED3D_OK;
2982 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 TRACE("(%p) : base_index %p\n", This, base_index);
2986 *base_index = This->stateBlock->baseVertexIndex;
2988 TRACE("Returning %u\n", *base_index);
2990 return WINED3D_OK;
2993 /*****
2994 * Get / Set Viewports
2995 *****/
2996 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 TRACE("(%p)\n", This);
3000 This->updateStateBlock->changed.viewport = TRUE;
3001 This->updateStateBlock->state.viewport = *pViewport;
3003 /* Handle recording of state blocks */
3004 if (This->isRecordingState) {
3005 TRACE("Recording... not performing anything\n");
3006 return WINED3D_OK;
3009 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3010 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3013 return WINED3D_OK;
3017 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3019 TRACE("(%p)\n", This);
3020 *pViewport = This->stateBlock->state.viewport;
3021 return WINED3D_OK;
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface,
3025 WINED3DRENDERSTATETYPE State, DWORD Value)
3027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 DWORD oldValue = This->stateBlock->state.render_states[State];
3030 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3032 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3033 This->updateStateBlock->state.render_states[State] = Value;
3035 /* Handle recording of state blocks */
3036 if (This->isRecordingState) {
3037 TRACE("Recording... not performing anything\n");
3038 return WINED3D_OK;
3041 /* Compared here and not before the assignment to allow proper stateblock recording */
3042 if(Value == oldValue) {
3043 TRACE("Application is setting the old value over, nothing to do\n");
3044 } else {
3045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3048 return WINED3D_OK;
3051 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface,
3052 WINED3DRENDERSTATETYPE State, DWORD *pValue)
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3058 *pValue = This->stateBlock->state.render_states[State];
3059 return WINED3D_OK;
3062 /*****
3063 * Get / Set Sampler States
3064 * TODO: Verify against dx9 definitions
3065 *****/
3067 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 DWORD oldValue;
3071 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3072 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3074 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3075 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3078 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3079 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3080 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3083 * SetSampler is designed to allow for more than the standard up to 8 textures
3084 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3085 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3087 * http://developer.nvidia.com/object/General_FAQ.html#t6
3089 * There are two new settings for GForce
3090 * the sampler one:
3091 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3092 * and the texture one:
3093 * GL_MAX_TEXTURE_COORDS_ARB.
3094 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3095 ******************/
3097 oldValue = This->stateBlock->samplerState[Sampler][Type];
3098 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3099 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3101 /* Handle recording of state blocks */
3102 if (This->isRecordingState) {
3103 TRACE("Recording... not performing anything\n");
3104 return WINED3D_OK;
3107 if(oldValue == Value) {
3108 TRACE("Application is setting the old value over, nothing to do\n");
3109 return WINED3D_OK;
3112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3114 return WINED3D_OK;
3117 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3121 This, Sampler, debug_d3dsamplerstate(Type), Type);
3123 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3124 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3127 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3128 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3129 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3131 *Value = This->stateBlock->samplerState[Sampler][Type];
3132 TRACE("(%p) : Returning %#x\n", This, *Value);
3134 return WINED3D_OK;
3137 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 This->updateStateBlock->changed.scissorRect = TRUE;
3141 if (EqualRect(&This->updateStateBlock->state.scissor_rect, pRect))
3143 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3144 return WINED3D_OK;
3146 CopyRect(&This->updateStateBlock->state.scissor_rect, pRect);
3148 if(This->isRecordingState) {
3149 TRACE("Recording... not performing anything\n");
3150 return WINED3D_OK;
3153 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3155 return WINED3D_OK;
3158 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 *pRect = This->updateStateBlock->state.scissor_rect;
3162 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3163 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3168 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3170 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3172 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3173 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3175 This->updateStateBlock->vertexDecl = pDecl;
3176 This->updateStateBlock->changed.vertexDecl = TRUE;
3178 if (This->isRecordingState) {
3179 TRACE("Recording... not performing anything\n");
3180 return WINED3D_OK;
3181 } else if(pDecl == oldDecl) {
3182 /* Checked after the assignment to allow proper stateblock recording */
3183 TRACE("Application is setting the old declaration over, nothing to do\n");
3184 return WINED3D_OK;
3187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3196 *ppDecl = This->stateBlock->vertexDecl;
3197 if (*ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3198 return WINED3D_OK;
3201 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3205 This->updateStateBlock->vertexShader = pShader;
3206 This->updateStateBlock->changed.vertexShader = TRUE;
3208 if (This->isRecordingState) {
3209 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3210 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3211 TRACE("Recording... not performing anything\n");
3212 return WINED3D_OK;
3213 } else if(oldShader == pShader) {
3214 /* Checked here to allow proper stateblock recording */
3215 TRACE("App is setting the old shader over, nothing to do\n");
3216 return WINED3D_OK;
3219 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3220 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3221 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3225 return WINED3D_OK;
3228 static IWineD3DVertexShader * WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface)
3230 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3231 IWineD3DVertexShader *shader;
3233 TRACE("iface %p.\n", iface);
3235 shader = device->stateBlock->vertexShader;
3236 if (shader) IWineD3DVertexShader_AddRef(shader);
3238 TRACE("Returning %p.\n", shader);
3239 return shader;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3243 IWineD3DDevice *iface,
3244 UINT start,
3245 CONST BOOL *srcData,
3246 UINT count) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3251 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3252 iface, srcData, start, count);
3254 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3256 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3257 for (i = 0; i < cnt; i++)
3258 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3260 for (i = start; i < cnt + start; ++i) {
3261 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3264 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3266 return WINED3D_OK;
3269 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3270 IWineD3DDevice *iface,
3271 UINT start,
3272 BOOL *dstData,
3273 UINT count) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 int cnt = min(count, MAX_CONST_B - start);
3278 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3279 iface, dstData, start, count);
3281 if (!dstData || cnt < 0)
3282 return WINED3DERR_INVALIDCALL;
3284 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3285 return WINED3D_OK;
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3289 IWineD3DDevice *iface,
3290 UINT start,
3291 CONST int *srcData,
3292 UINT count) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3297 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3298 iface, srcData, start, count);
3300 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3302 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3303 for (i = 0; i < cnt; i++)
3304 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3305 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3307 for (i = start; i < cnt + start; ++i) {
3308 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3311 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3313 return WINED3D_OK;
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3317 IWineD3DDevice *iface,
3318 UINT start,
3319 int *dstData,
3320 UINT count) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 int cnt = min(count, MAX_CONST_I - start);
3325 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326 iface, dstData, start, count);
3328 if (!dstData || ((signed int)MAX_CONST_I - (signed int)start) <= 0)
3329 return WINED3DERR_INVALIDCALL;
3331 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3332 return WINED3D_OK;
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3336 IWineD3DDevice *iface,
3337 UINT start,
3338 CONST float *srcData,
3339 UINT count) {
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342 UINT i;
3344 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3345 iface, srcData, start, count);
3347 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3348 if (!srcData || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3349 return WINED3DERR_INVALIDCALL;
3351 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3352 if(TRACE_ON(d3d)) {
3353 for (i = 0; i < count; i++)
3354 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3355 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3358 if (!This->isRecordingState)
3360 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3364 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3365 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3367 return WINED3D_OK;
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3371 IWineD3DDevice *iface,
3372 UINT start,
3373 float *dstData,
3374 UINT count) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 int cnt = min(count, This->d3d_vshader_constantF - start);
3379 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3380 iface, dstData, start, count);
3382 if (!dstData || cnt < 0)
3383 return WINED3DERR_INVALIDCALL;
3385 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3386 return WINED3D_OK;
3389 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3390 DWORD i;
3391 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3397 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3399 DWORD i = This->rev_tex_unit_map[unit];
3400 DWORD j = This->texUnitMap[stage];
3402 This->texUnitMap[stage] = unit;
3403 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3405 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3408 This->rev_tex_unit_map[unit] = stage;
3409 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3411 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3415 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3416 int i;
3418 This->fixed_function_usage_map = 0;
3419 for (i = 0; i < MAX_TEXTURES; ++i) {
3420 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3421 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3422 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3423 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3424 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3425 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3426 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3427 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3429 if (color_op == WINED3DTOP_DISABLE) {
3430 /* Not used, and disable higher stages */
3431 break;
3434 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3435 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3436 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3437 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3438 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3439 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3440 This->fixed_function_usage_map |= (1 << i);
3443 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3444 This->fixed_function_usage_map |= (1 << (i + 1));
3449 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3451 unsigned int i, tex;
3452 WORD ffu_map;
3454 device_update_fixed_function_usage_map(This);
3455 ffu_map = This->fixed_function_usage_map;
3457 if (This->max_ffp_textures == gl_info->limits.texture_stages
3458 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3460 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3462 if (!(ffu_map & 1)) continue;
3464 if (This->texUnitMap[i] != i) {
3465 device_map_stage(This, i, i);
3466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3467 markTextureStagesDirty(This, i);
3470 return;
3473 /* Now work out the mapping */
3474 tex = 0;
3475 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3477 if (!(ffu_map & 1)) continue;
3479 if (This->texUnitMap[i] != tex) {
3480 device_map_stage(This, i, tex);
3481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3482 markTextureStagesDirty(This, i);
3485 ++tex;
3489 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3491 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3492 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3493 unsigned int i;
3495 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3496 if (sampler_type[i] && This->texUnitMap[i] != i)
3498 device_map_stage(This, i, i);
3499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3500 if (i < gl_info->limits.texture_stages)
3502 markTextureStagesDirty(This, i);
3508 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3509 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3511 DWORD current_mapping = This->rev_tex_unit_map[unit];
3513 /* Not currently used */
3514 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3516 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3517 /* Used by a fragment sampler */
3519 if (!pshader_sampler_tokens) {
3520 /* No pixel shader, check fixed function */
3521 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3524 /* Pixel shader, check the shader's sampler map */
3525 return !pshader_sampler_tokens[current_mapping];
3528 /* Used by a vertex sampler */
3529 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3532 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3534 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3535 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3536 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3537 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3538 int i;
3540 if (ps) {
3541 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3543 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3544 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3545 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3548 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3549 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3550 if (vshader_sampler_type[i])
3552 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3554 /* Already mapped somewhere */
3555 continue;
3558 while (start >= 0) {
3559 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3561 device_map_stage(This, vsampler_idx, start);
3562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3564 --start;
3565 break;
3568 --start;
3574 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3576 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3577 BOOL vs = use_vs(This->stateBlock);
3578 BOOL ps = use_ps(This->stateBlock);
3580 * Rules are:
3581 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3582 * that would be really messy and require shader recompilation
3583 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3584 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3586 if (ps) device_map_psamplers(This, gl_info);
3587 else device_map_fixed_function_samplers(This, gl_info);
3589 if (vs) device_map_vsamplers(This, ps, gl_info);
3592 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3595 This->updateStateBlock->pixelShader = pShader;
3596 This->updateStateBlock->changed.pixelShader = TRUE;
3598 /* Handle recording of state blocks */
3599 if (This->isRecordingState) {
3600 TRACE("Recording... not performing anything\n");
3603 if (This->isRecordingState) {
3604 TRACE("Recording... not performing anything\n");
3605 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3606 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3607 return WINED3D_OK;
3610 if(pShader == oldShader) {
3611 TRACE("App is setting the old pixel shader over, nothing to do\n");
3612 return WINED3D_OK;
3615 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3616 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3618 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3621 return WINED3D_OK;
3624 static IWineD3DPixelShader * WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface)
3626 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
3627 IWineD3DPixelShader *shader;
3629 TRACE("iface %p.\n", iface);
3631 shader = device->stateBlock->pixelShader;
3632 if (shader) IWineD3DPixelShader_AddRef(shader);
3634 TRACE("Returning %p.\n", shader);
3635 return shader;
3638 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3639 IWineD3DDevice *iface,
3640 UINT start,
3641 CONST BOOL *srcData,
3642 UINT count) {
3644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3645 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3647 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3648 iface, srcData, start, count);
3650 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3652 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3653 for (i = 0; i < cnt; i++)
3654 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3656 for (i = start; i < cnt + start; ++i) {
3657 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3660 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3662 return WINED3D_OK;
3665 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3666 IWineD3DDevice *iface,
3667 UINT start,
3668 BOOL *dstData,
3669 UINT count) {
3671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3672 int cnt = min(count, MAX_CONST_B - start);
3674 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3675 iface, dstData, start, count);
3677 if (!dstData || cnt < 0)
3678 return WINED3DERR_INVALIDCALL;
3680 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3681 return WINED3D_OK;
3684 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3685 IWineD3DDevice *iface,
3686 UINT start,
3687 CONST int *srcData,
3688 UINT count) {
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3693 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3694 iface, srcData, start, count);
3696 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3698 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3699 for (i = 0; i < cnt; i++)
3700 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3701 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3703 for (i = start; i < cnt + start; ++i) {
3704 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3707 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3709 return WINED3D_OK;
3712 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3713 IWineD3DDevice *iface,
3714 UINT start,
3715 int *dstData,
3716 UINT count) {
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 int cnt = min(count, MAX_CONST_I - start);
3721 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3722 iface, dstData, start, count);
3724 if (!dstData || cnt < 0)
3725 return WINED3DERR_INVALIDCALL;
3727 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3728 return WINED3D_OK;
3731 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3732 IWineD3DDevice *iface,
3733 UINT start,
3734 CONST float *srcData,
3735 UINT count) {
3737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3738 UINT i;
3740 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3741 iface, srcData, start, count);
3743 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3744 if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3745 return WINED3DERR_INVALIDCALL;
3747 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3748 if(TRACE_ON(d3d)) {
3749 for (i = 0; i < count; i++)
3750 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3751 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3754 if (!This->isRecordingState)
3756 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3760 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3761 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3763 return WINED3D_OK;
3766 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3767 IWineD3DDevice *iface,
3768 UINT start,
3769 float *dstData,
3770 UINT count) {
3772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3773 int cnt = min(count, This->d3d_pshader_constantF - start);
3775 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3776 iface, dstData, start, count);
3778 if (!dstData || cnt < 0)
3779 return WINED3DERR_INVALIDCALL;
3781 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3782 return WINED3D_OK;
3785 /* Context activation is done by the caller. */
3786 /* Do not call while under the GL lock. */
3787 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3788 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3789 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3790 DWORD DestFVF)
3792 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3793 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3794 unsigned int i;
3795 WINED3DVIEWPORT vp;
3796 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3797 BOOL doClip;
3798 DWORD numTextures;
3800 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3802 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3805 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3807 ERR("Source has no position mask\n");
3808 return WINED3DERR_INVALIDCALL;
3811 if (!dest->resource.allocatedMemory)
3812 buffer_get_sysmem(dest, gl_info);
3814 /* Get a pointer into the destination vbo(create one if none exists) and
3815 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3817 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3819 dest->flags |= WINED3D_BUFFER_CREATEBO;
3820 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3823 if (dest->buffer_object)
3825 unsigned char extrabytes = 0;
3826 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3827 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3828 * this may write 4 extra bytes beyond the area that should be written
3830 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3831 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3832 if(!dest_conv_addr) {
3833 ERR("Out of memory\n");
3834 /* Continue without storing converted vertices */
3836 dest_conv = dest_conv_addr;
3839 if (This->stateBlock->state.render_states[WINED3DRS_CLIPPING])
3841 static BOOL warned = FALSE;
3843 * The clipping code is not quite correct. Some things need
3844 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3845 * so disable clipping for now.
3846 * (The graphics in Half-Life are broken, and my processvertices
3847 * test crashes with IDirect3DDevice3)
3848 doClip = TRUE;
3850 doClip = FALSE;
3851 if(!warned) {
3852 warned = TRUE;
3853 FIXME("Clipping is broken and disabled for now\n");
3855 } else doClip = FALSE;
3856 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3858 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3859 WINED3DTS_VIEW,
3860 &view_mat);
3861 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3862 WINED3DTS_PROJECTION,
3863 &proj_mat);
3864 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3865 WINED3DTS_WORLDMATRIX(0),
3866 &world_mat);
3868 TRACE("View mat:\n");
3869 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);
3870 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);
3871 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);
3872 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);
3874 TRACE("Proj mat:\n");
3875 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);
3876 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);
3877 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);
3878 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);
3880 TRACE("World mat:\n");
3881 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);
3882 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);
3883 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);
3884 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);
3886 /* Get the viewport */
3887 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3888 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3889 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3891 multiply_matrix(&mat,&view_mat,&world_mat);
3892 multiply_matrix(&mat,&proj_mat,&mat);
3894 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3896 for (i = 0; i < dwCount; i+= 1) {
3897 unsigned int tex_index;
3899 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3900 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3901 /* The position first */
3902 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3903 const float *p = (const float *)(element->data + i * element->stride);
3904 float x, y, z, rhw;
3905 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3907 /* Multiplication with world, view and projection matrix */
3908 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);
3909 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);
3910 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);
3911 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);
3913 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3915 /* WARNING: The following things are taken from d3d7 and were not yet checked
3916 * against d3d8 or d3d9!
3919 /* Clipping conditions: From msdn
3921 * A vertex is clipped if it does not match the following requirements
3922 * -rhw < x <= rhw
3923 * -rhw < y <= rhw
3924 * 0 < z <= rhw
3925 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3927 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3928 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3932 if( !doClip ||
3933 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3934 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3935 ( rhw > eps ) ) ) {
3937 /* "Normal" viewport transformation (not clipped)
3938 * 1) The values are divided by rhw
3939 * 2) The y axis is negative, so multiply it with -1
3940 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3941 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3942 * 4) Multiply x with Width/2 and add Width/2
3943 * 5) The same for the height
3944 * 6) Add the viewpoint X and Y to the 2D coordinates and
3945 * The minimum Z value to z
3946 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3948 * Well, basically it's simply a linear transformation into viewport
3949 * coordinates
3952 x /= rhw;
3953 y /= rhw;
3954 z /= rhw;
3956 y *= -1;
3958 x *= vp.Width / 2;
3959 y *= vp.Height / 2;
3960 z *= vp.MaxZ - vp.MinZ;
3962 x += vp.Width / 2 + vp.X;
3963 y += vp.Height / 2 + vp.Y;
3964 z += vp.MinZ;
3966 rhw = 1 / rhw;
3967 } else {
3968 /* That vertex got clipped
3969 * Contrary to OpenGL it is not dropped completely, it just
3970 * undergoes a different calculation.
3972 TRACE("Vertex got clipped\n");
3973 x += rhw;
3974 y += rhw;
3976 x /= 2;
3977 y /= 2;
3979 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3980 * outside of the main vertex buffer memory. That needs some more
3981 * investigation...
3985 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3988 ( (float *) dest_ptr)[0] = x;
3989 ( (float *) dest_ptr)[1] = y;
3990 ( (float *) dest_ptr)[2] = z;
3991 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3993 dest_ptr += 3 * sizeof(float);
3995 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3996 dest_ptr += sizeof(float);
3999 if(dest_conv) {
4000 float w = 1 / rhw;
4001 ( (float *) dest_conv)[0] = x * w;
4002 ( (float *) dest_conv)[1] = y * w;
4003 ( (float *) dest_conv)[2] = z * w;
4004 ( (float *) dest_conv)[3] = w;
4006 dest_conv += 3 * sizeof(float);
4008 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4009 dest_conv += sizeof(float);
4013 if (DestFVF & WINED3DFVF_PSIZE) {
4014 dest_ptr += sizeof(DWORD);
4015 if(dest_conv) dest_conv += sizeof(DWORD);
4017 if (DestFVF & WINED3DFVF_NORMAL) {
4018 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4019 const float *normal = (const float *)(element->data + i * element->stride);
4020 /* AFAIK this should go into the lighting information */
4021 FIXME("Didn't expect the destination to have a normal\n");
4022 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4023 if(dest_conv) {
4024 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4028 if (DestFVF & WINED3DFVF_DIFFUSE) {
4029 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4030 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4031 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4033 static BOOL warned = FALSE;
4035 if(!warned) {
4036 ERR("No diffuse color in source, but destination has one\n");
4037 warned = TRUE;
4040 *( (DWORD *) dest_ptr) = 0xffffffff;
4041 dest_ptr += sizeof(DWORD);
4043 if(dest_conv) {
4044 *( (DWORD *) dest_conv) = 0xffffffff;
4045 dest_conv += sizeof(DWORD);
4048 else {
4049 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4050 if(dest_conv) {
4051 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4052 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4053 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4054 dest_conv += sizeof(DWORD);
4059 if (DestFVF & WINED3DFVF_SPECULAR)
4061 /* What's the color value in the feedback buffer? */
4062 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4063 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4064 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4066 static BOOL warned = FALSE;
4068 if(!warned) {
4069 ERR("No specular color in source, but destination has one\n");
4070 warned = TRUE;
4073 *( (DWORD *) dest_ptr) = 0xFF000000;
4074 dest_ptr += sizeof(DWORD);
4076 if(dest_conv) {
4077 *( (DWORD *) dest_conv) = 0xFF000000;
4078 dest_conv += sizeof(DWORD);
4081 else {
4082 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4083 if(dest_conv) {
4084 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4085 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4086 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4087 dest_conv += sizeof(DWORD);
4092 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4093 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4094 const float *tex_coord = (const float *)(element->data + i * element->stride);
4095 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4097 ERR("No source texture, but destination requests one\n");
4098 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4099 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4101 else {
4102 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4103 if(dest_conv) {
4104 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4110 if (dest_conv)
4112 ENTER_GL();
4114 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4115 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4116 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4117 dwCount * get_flexible_vertex_size(DestFVF),
4118 dest_conv_addr));
4119 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4121 LEAVE_GL();
4123 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4126 return WINED3D_OK;
4128 #undef copy_and_next
4130 /* Do not call while under the GL lock. */
4131 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4132 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4133 DWORD DestFVF)
4135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4136 struct wined3d_stream_info stream_info;
4137 const struct wined3d_gl_info *gl_info;
4138 struct wined3d_context *context;
4139 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4140 HRESULT hr;
4142 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4144 if(pVertexDecl) {
4145 ERR("Output vertex declaration not implemented yet\n");
4148 /* Need any context to write to the vbo. */
4149 context = context_acquire(This, NULL);
4150 gl_info = context->gl_info;
4152 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4153 * control the streamIsUP flag, thus restore it afterwards.
4155 This->stateBlock->streamIsUP = FALSE;
4156 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4157 This->stateBlock->streamIsUP = streamWasUP;
4159 if(vbo || SrcStartIndex) {
4160 unsigned int i;
4161 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4162 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4164 * Also get the start index in, but only loop over all elements if there's something to add at all.
4166 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4168 struct wined3d_stream_info_element *e;
4170 if (!(stream_info.use_map & (1 << i))) continue;
4172 e = &stream_info.elements[i];
4173 if (e->buffer_object)
4175 struct wined3d_buffer *vb = This->stateBlock->streams[e->stream_idx].buffer;
4176 e->buffer_object = 0;
4177 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4178 ENTER_GL();
4179 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4180 vb->buffer_object = 0;
4181 LEAVE_GL();
4183 if (e->data) e->data += e->stride * SrcStartIndex;
4187 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4188 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4190 context_release(context);
4192 return hr;
4195 /*****
4196 * Get / Set Texture Stage States
4197 * TODO: Verify against dx9 definitions
4198 *****/
4199 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value)
4201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4202 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4203 DWORD oldValue;
4205 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4207 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4209 WARN("Invalid Type %d passed.\n", Type);
4210 return WINED3D_OK;
4213 if (Stage >= gl_info->limits.texture_stages)
4215 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4216 Stage, gl_info->limits.texture_stages - 1);
4217 return WINED3D_OK;
4220 oldValue = This->updateStateBlock->textureState[Stage][Type];
4221 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4222 This->updateStateBlock->textureState[Stage][Type] = Value;
4224 if (This->isRecordingState) {
4225 TRACE("Recording... not performing anything\n");
4226 return WINED3D_OK;
4229 /* Checked after the assignments to allow proper stateblock recording */
4230 if(oldValue == Value) {
4231 TRACE("App is setting the old value over, nothing to do\n");
4232 return WINED3D_OK;
4235 if(Stage > This->stateBlock->lowest_disabled_stage &&
4236 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4237 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4238 * Changes in other states are important on disabled stages too
4240 return WINED3D_OK;
4243 if(Type == WINED3DTSS_COLOROP) {
4244 unsigned int i;
4246 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4247 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4248 * they have to be disabled
4250 * The current stage is dirtified below.
4252 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4253 TRACE("Additionally dirtifying stage %u\n", i);
4254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4256 This->stateBlock->lowest_disabled_stage = Stage;
4257 TRACE("New lowest disabled: %u\n", Stage);
4258 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4259 /* Previously disabled stage enabled. Stages above it may need enabling
4260 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4261 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4263 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4266 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4268 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4269 break;
4271 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4274 This->stateBlock->lowest_disabled_stage = i;
4275 TRACE("New lowest disabled: %u\n", i);
4279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4281 return WINED3D_OK;
4284 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD *pValue)
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 if (Type > WINED3D_HIGHEST_TEXTURE_STATE)
4290 WARN("Invalid Type %d passed.\n", Type);
4291 return WINED3D_OK;
4294 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4296 *pValue = This->updateStateBlock->textureState[Stage][Type];
4297 return WINED3D_OK;
4300 /*****
4301 * Get / Set Texture
4302 *****/
4303 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4304 DWORD stage, IWineD3DBaseTexture *texture)
4306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4307 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4308 IWineD3DBaseTexture *prev;
4310 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4312 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4313 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4315 /* Windows accepts overflowing this array... we do not. */
4316 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4318 WARN("Ignoring invalid stage %u.\n", stage);
4319 return WINED3D_OK;
4322 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4323 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4325 WARN("Rejecting attempt to set scratch texture.\n");
4326 return WINED3DERR_INVALIDCALL;
4329 This->updateStateBlock->changed.textures |= 1 << stage;
4331 prev = This->updateStateBlock->textures[stage];
4332 TRACE("Previous texture %p.\n", prev);
4334 if (texture == prev)
4336 TRACE("App is setting the same texture again, nothing to do.\n");
4337 return WINED3D_OK;
4340 TRACE("Setting new texture to %p.\n", texture);
4341 This->updateStateBlock->textures[stage] = texture;
4343 if (This->isRecordingState)
4345 TRACE("Recording... not performing anything\n");
4347 if (texture) IWineD3DBaseTexture_AddRef(texture);
4348 if (prev) IWineD3DBaseTexture_Release(prev);
4350 return WINED3D_OK;
4353 if (texture)
4355 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4356 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4357 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4359 IWineD3DBaseTexture_AddRef(texture);
4361 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4366 if (!prev && stage < gl_info->limits.texture_stages)
4368 /* The source arguments for color and alpha ops have different
4369 * meanings when a NULL texture is bound, so the COLOROP and
4370 * ALPHAOP have to be dirtified. */
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4375 if (bind_count == 1) t->baseTexture.sampler = stage;
4378 if (prev)
4380 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4381 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4383 IWineD3DBaseTexture_Release(prev);
4385 if (!texture && stage < gl_info->limits.texture_stages)
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4391 if (bind_count && t->baseTexture.sampler == stage)
4393 unsigned int i;
4395 /* Search for other stages the texture is bound to. Shouldn't
4396 * happen if applications bind textures to a single stage only. */
4397 TRACE("Searching for other stages the texture is bound to.\n");
4398 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4400 if (This->updateStateBlock->textures[i] == prev)
4402 TRACE("Texture is also bound to stage %u.\n", i);
4403 t->baseTexture.sampler = i;
4404 break;
4410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4412 return WINED3D_OK;
4415 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4418 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4420 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4421 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4424 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4425 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4426 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4429 *ppTexture=This->stateBlock->textures[Stage];
4430 if (*ppTexture)
4431 IWineD3DBaseTexture_AddRef(*ppTexture);
4433 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4435 return WINED3D_OK;
4438 /*****
4439 * Get Back Buffer
4440 *****/
4441 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4442 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4444 IWineD3DSwapChain *swapchain;
4445 HRESULT hr;
4447 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4448 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4450 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4451 if (FAILED(hr))
4453 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4454 return hr;
4457 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4458 IWineD3DSwapChain_Release(swapchain);
4459 if (FAILED(hr))
4461 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4462 return hr;
4465 return WINED3D_OK;
4468 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 WARN("(%p) : stub, calling idirect3d for now\n", This);
4471 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4474 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 IWineD3DSwapChain *swapChain;
4477 HRESULT hr;
4479 if(iSwapChain > 0) {
4480 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4481 if (hr == WINED3D_OK) {
4482 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4483 IWineD3DSwapChain_Release(swapChain);
4484 } else {
4485 FIXME("(%p) Error getting display mode\n", This);
4487 } else {
4488 /* Don't read the real display mode,
4489 but return the stored mode instead. X11 can't change the color
4490 depth, and some apps are pretty angry if they SetDisplayMode from
4491 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4493 Also don't relay to the swapchain because with ddraw it's possible
4494 that there isn't a swapchain at all */
4495 pMode->Width = This->ddraw_width;
4496 pMode->Height = This->ddraw_height;
4497 pMode->Format = This->ddraw_format;
4498 pMode->RefreshRate = 0;
4499 hr = WINED3D_OK;
4502 return hr;
4505 /*****
4506 * Stateblock related functions
4507 *****/
4509 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 IWineD3DStateBlock *stateblock;
4512 HRESULT hr;
4514 TRACE("(%p)\n", This);
4516 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4518 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4519 if (FAILED(hr)) return hr;
4521 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4522 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4523 This->isRecordingState = TRUE;
4525 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4527 return WINED3D_OK;
4530 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4532 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4534 if (!This->isRecordingState) {
4535 WARN("(%p) not recording! returning error\n", This);
4536 *ppStateBlock = NULL;
4537 return WINED3DERR_INVALIDCALL;
4540 stateblock_init_contained_states(object);
4542 *ppStateBlock = (IWineD3DStateBlock*) object;
4543 This->isRecordingState = FALSE;
4544 This->updateStateBlock = This->stateBlock;
4545 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4546 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4547 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4548 return WINED3D_OK;
4551 /*****
4552 * Scene related functions
4553 *****/
4554 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4555 /* At the moment we have no need for any functionality at the beginning
4556 of a scene */
4557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4558 TRACE("(%p)\n", This);
4560 if(This->inScene) {
4561 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4562 return WINED3DERR_INVALIDCALL;
4564 This->inScene = TRUE;
4565 return WINED3D_OK;
4568 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4571 struct wined3d_context *context;
4573 TRACE("(%p)\n", This);
4575 if(!This->inScene) {
4576 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4577 return WINED3DERR_INVALIDCALL;
4580 context = context_acquire(This, NULL);
4581 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4582 wglFlush();
4583 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4584 * fails. */
4585 context_release(context);
4587 This->inScene = FALSE;
4588 return WINED3D_OK;
4591 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4592 const RECT *pSourceRect, const RECT *pDestRect,
4593 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4595 IWineD3DSwapChain *swapChain = NULL;
4596 int i;
4597 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4599 TRACE("iface %p.\n", iface);
4601 for(i = 0 ; i < swapchains ; i ++) {
4603 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4604 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4605 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4606 IWineD3DSwapChain_Release(swapChain);
4609 return WINED3D_OK;
4612 /* Do not call while under the GL lock. */
4613 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD rect_count,
4614 const RECT *rects, DWORD flags, WINED3DCOLOR color, float depth, DWORD stencil)
4616 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4617 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
4618 RECT draw_rect;
4620 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4621 iface, rect_count, rects, flags, color, depth, stencil);
4623 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !device->depth_stencil)
4625 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4626 /* TODO: What about depth stencil buffers without stencil bits? */
4627 return WINED3DERR_INVALIDCALL;
4630 device_get_draw_rect(device, &draw_rect);
4632 return device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
4633 device->render_targets, rect_count, rects, &draw_rect, flags, &c, depth, stencil);
4636 /*****
4637 * Drawing functions
4638 *****/
4640 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4641 WINED3DPRIMITIVETYPE primitive_type)
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4647 This->updateStateBlock->changed.primitive_type = TRUE;
4648 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4651 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4652 WINED3DPRIMITIVETYPE *primitive_type)
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4658 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4660 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4663 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4667 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4669 if(!This->stateBlock->vertexDecl) {
4670 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4671 return WINED3DERR_INVALIDCALL;
4674 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4675 if(This->stateBlock->streamIsUP) {
4676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4677 This->stateBlock->streamIsUP = FALSE;
4680 if (This->stateBlock->loadBaseVertexIndex)
4682 This->stateBlock->loadBaseVertexIndex = 0;
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4685 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4686 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4687 return WINED3D_OK;
4690 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4693 UINT idxStride = 2;
4694 IWineD3DBuffer *pIB;
4695 GLuint vbo;
4697 pIB = This->stateBlock->pIndexData;
4698 if (!pIB) {
4699 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4700 * without an index buffer set. (The first time at least...)
4701 * D3D8 simply dies, but I doubt it can do much harm to return
4702 * D3DERR_INVALIDCALL there as well. */
4703 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4704 return WINED3DERR_INVALIDCALL;
4707 if(!This->stateBlock->vertexDecl) {
4708 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4709 return WINED3DERR_INVALIDCALL;
4712 if(This->stateBlock->streamIsUP) {
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4714 This->stateBlock->streamIsUP = FALSE;
4716 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4718 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4720 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4721 idxStride = 2;
4722 } else {
4723 idxStride = 4;
4726 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4727 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4731 drawPrimitive(iface, index_count, startIndex, idxStride,
4732 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4734 return WINED3D_OK;
4737 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4738 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 struct wined3d_stream_state *stream;
4742 IWineD3DBuffer *vb;
4744 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4745 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4747 if(!This->stateBlock->vertexDecl) {
4748 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4749 return WINED3DERR_INVALIDCALL;
4752 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4753 stream = &This->stateBlock->streams[0];
4754 vb = (IWineD3DBuffer *)stream->buffer;
4755 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4756 if (vb) IWineD3DBuffer_Release(vb);
4757 stream->offset = 0;
4758 stream->stride = VertexStreamZeroStride;
4759 This->stateBlock->streamIsUP = TRUE;
4760 This->stateBlock->loadBaseVertexIndex = 0;
4762 /* TODO: Only mark dirty if drawing from a different UP address */
4763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4765 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4767 /* MSDN specifies stream zero settings must be set to NULL */
4768 stream->buffer = NULL;
4769 stream->stride = 0;
4771 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4772 * the new stream sources or use UP drawing again
4774 return WINED3D_OK;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4778 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4779 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4781 int idxStride;
4782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4783 struct wined3d_stream_state *stream;
4784 IWineD3DBuffer *vb;
4785 IWineD3DBuffer *ib;
4787 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4788 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4790 if(!This->stateBlock->vertexDecl) {
4791 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4792 return WINED3DERR_INVALIDCALL;
4795 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4796 idxStride = 2;
4797 } else {
4798 idxStride = 4;
4801 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4802 stream = &This->stateBlock->streams[0];
4803 vb = (IWineD3DBuffer *)stream->buffer;
4804 stream->buffer = (struct wined3d_buffer *)pVertexStreamZeroData;
4805 if (vb) IWineD3DBuffer_Release(vb);
4806 stream->offset = 0;
4807 stream->stride = VertexStreamZeroStride;
4808 This->stateBlock->streamIsUP = TRUE;
4810 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4811 This->stateBlock->baseVertexIndex = 0;
4812 This->stateBlock->loadBaseVertexIndex = 0;
4813 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4817 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4819 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4820 stream->buffer = NULL;
4821 stream->stride = 0;
4822 ib = This->stateBlock->pIndexData;
4823 if(ib) {
4824 IWineD3DBuffer_Release(ib);
4825 This->stateBlock->pIndexData = NULL;
4827 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4828 * SetStreamSource to specify a vertex buffer
4831 return WINED3D_OK;
4834 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4835 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4839 /* Mark the state dirty until we have nicer tracking
4840 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4841 * that value.
4843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4845 This->stateBlock->baseVertexIndex = 0;
4846 This->up_strided = DrawPrimStrideData;
4847 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4848 This->up_strided = NULL;
4849 return WINED3D_OK;
4852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4853 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4854 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4857 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4859 /* Mark the state dirty until we have nicer tracking
4860 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4861 * that value.
4863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4865 This->stateBlock->streamIsUP = TRUE;
4866 This->stateBlock->baseVertexIndex = 0;
4867 This->up_strided = DrawPrimStrideData;
4868 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4869 This->up_strided = NULL;
4870 return WINED3D_OK;
4873 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4874 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4875 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4877 WINED3DLOCKED_BOX src;
4878 WINED3DLOCKED_BOX dst;
4879 HRESULT hr;
4881 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4882 iface, pSourceVolume, pDestinationVolume);
4884 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4885 * dirtification to improve loading performance.
4887 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4888 if(FAILED(hr)) return hr;
4889 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4890 if(FAILED(hr)) {
4891 IWineD3DVolume_UnlockBox(pSourceVolume);
4892 return hr;
4895 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4897 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4898 if(FAILED(hr)) {
4899 IWineD3DVolume_UnlockBox(pSourceVolume);
4900 } else {
4901 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4903 return hr;
4906 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4907 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4909 unsigned int level_count, i;
4910 WINED3DRESOURCETYPE type;
4911 HRESULT hr;
4913 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4915 /* Verify that the source and destination textures are non-NULL. */
4916 if (!src_texture || !dst_texture)
4918 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4919 return WINED3DERR_INVALIDCALL;
4922 if (src_texture == dst_texture)
4924 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4925 return WINED3DERR_INVALIDCALL;
4928 /* Verify that the source and destination textures are the same type. */
4929 type = IWineD3DBaseTexture_GetType(src_texture);
4930 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4932 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4933 return WINED3DERR_INVALIDCALL;
4936 /* Check that both textures have the identical numbers of levels. */
4937 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4938 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4940 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4941 return WINED3DERR_INVALIDCALL;
4944 /* Make sure that the destination texture is loaded. */
4945 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4947 /* Update every surface level of the texture. */
4948 switch (type)
4950 case WINED3DRTYPE_TEXTURE:
4952 IWineD3DSurface *src_surface;
4953 IWineD3DSurface *dst_surface;
4955 for (i = 0; i < level_count; ++i)
4957 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4958 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4959 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4960 IWineD3DSurface_Release(dst_surface);
4961 IWineD3DSurface_Release(src_surface);
4962 if (FAILED(hr))
4964 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4965 return hr;
4968 break;
4971 case WINED3DRTYPE_CUBETEXTURE:
4973 IWineD3DSurface *src_surface;
4974 IWineD3DSurface *dst_surface;
4975 WINED3DCUBEMAP_FACES face;
4977 for (i = 0; i < level_count; ++i)
4979 /* Update each cube face. */
4980 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4982 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4983 face, i, &src_surface);
4984 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4985 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4986 face, i, &dst_surface);
4987 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4988 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4989 IWineD3DSurface_Release(dst_surface);
4990 IWineD3DSurface_Release(src_surface);
4991 if (FAILED(hr))
4993 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4994 return hr;
4998 break;
5001 case WINED3DRTYPE_VOLUMETEXTURE:
5003 IWineD3DVolume *src_volume;
5004 IWineD3DVolume *dst_volume;
5006 for (i = 0; i < level_count; ++i)
5008 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5009 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5010 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5011 IWineD3DVolume_Release(dst_volume);
5012 IWineD3DVolume_Release(src_volume);
5013 if (FAILED(hr))
5015 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5016 return hr;
5019 break;
5022 default:
5023 FIXME("Unsupported texture type %#x.\n", type);
5024 return WINED3DERR_INVALIDCALL;
5027 return WINED3D_OK;
5030 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
5031 UINT swapchain_idx, IWineD3DSurface *dst_surface)
5033 IWineD3DSwapChain *swapchain;
5034 HRESULT hr;
5036 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5038 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5039 if (FAILED(hr)) return hr;
5041 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5042 IWineD3DSwapChain_Release(swapchain);
5044 return hr;
5047 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5049 IWineD3DBaseTextureImpl *texture;
5050 DWORD i;
5052 TRACE("(%p) : %p\n", This, pNumPasses);
5054 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5055 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5056 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5057 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5059 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5060 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5061 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5064 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5065 if (!texture || texture->resource.format->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5067 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5068 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5069 return E_FAIL;
5071 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5072 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5073 return E_FAIL;
5075 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5076 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5077 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5078 return E_FAIL;
5082 /* return a sensible default */
5083 *pNumPasses = 1;
5085 TRACE("returning D3D_OK\n");
5086 return WINED3D_OK;
5089 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5091 int i;
5093 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5095 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5096 if (texture && (texture->resource.format->id == WINED3DFMT_P8_UINT
5097 || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM))
5099 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5104 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 int j;
5107 UINT NewSize;
5108 PALETTEENTRY **palettes;
5110 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5112 if (PaletteNumber >= MAX_PALETTES) {
5113 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5114 return WINED3DERR_INVALIDCALL;
5117 if (PaletteNumber >= This->NumberOfPalettes) {
5118 NewSize = This->NumberOfPalettes;
5119 do {
5120 NewSize *= 2;
5121 } while(PaletteNumber >= NewSize);
5122 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5123 if (!palettes) {
5124 ERR("Out of memory!\n");
5125 return E_OUTOFMEMORY;
5127 This->palettes = palettes;
5128 This->NumberOfPalettes = NewSize;
5131 if (!This->palettes[PaletteNumber]) {
5132 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5133 if (!This->palettes[PaletteNumber]) {
5134 ERR("Out of memory!\n");
5135 return E_OUTOFMEMORY;
5139 for (j = 0; j < 256; ++j) {
5140 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5141 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5142 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5143 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5145 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5146 TRACE("(%p) : returning\n", This);
5147 return WINED3D_OK;
5150 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5152 int j;
5153 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5154 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5155 /* What happens in such situation isn't documented; Native seems to silently abort
5156 on such conditions. Return Invalid Call. */
5157 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5158 return WINED3DERR_INVALIDCALL;
5160 for (j = 0; j < 256; ++j) {
5161 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5162 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5163 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5164 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5166 TRACE("(%p) : returning\n", This);
5167 return WINED3D_OK;
5170 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5172 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5173 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5174 (tested with reference rasterizer). Return Invalid Call. */
5175 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5176 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5177 return WINED3DERR_INVALIDCALL;
5179 /*TODO: stateblocks */
5180 if (This->currentPalette != PaletteNumber) {
5181 This->currentPalette = PaletteNumber;
5182 dirtify_p8_texture_samplers(This);
5184 TRACE("(%p) : returning\n", This);
5185 return WINED3D_OK;
5188 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 if (!PaletteNumber)
5193 WARN("(%p) : returning Invalid Call\n", This);
5194 return WINED3DERR_INVALIDCALL;
5196 /*TODO: stateblocks */
5197 *PaletteNumber = This->currentPalette;
5198 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5199 return WINED3D_OK;
5202 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5204 static BOOL warned;
5205 if (!warned)
5207 FIXME("(%p) : stub\n", This);
5208 warned = TRUE;
5211 This->softwareVertexProcessing = bSoftware;
5212 return WINED3D_OK;
5216 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5218 static BOOL warned;
5219 if (!warned)
5221 FIXME("(%p) : stub\n", This);
5222 warned = TRUE;
5224 return This->softwareVertexProcessing;
5227 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5228 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5230 IWineD3DSwapChain *swapchain;
5231 HRESULT hr;
5233 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5234 iface, swapchain_idx, raster_status);
5236 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5237 if (FAILED(hr))
5239 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5240 return hr;
5243 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5244 IWineD3DSwapChain_Release(swapchain);
5245 if (FAILED(hr))
5247 WARN("Failed to get raster status, hr %#x.\n", hr);
5248 return hr;
5251 return WINED3D_OK;
5254 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5256 static BOOL warned;
5257 if(nSegments != 0.0f) {
5258 if (!warned)
5260 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5261 warned = TRUE;
5264 return WINED3D_OK;
5267 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5269 static BOOL warned;
5270 if (!warned)
5272 FIXME("iface %p stub!\n", iface);
5273 warned = TRUE;
5275 return 0.0f;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5279 IWineD3DSurface *src_surface, const RECT *src_rect,
5280 IWineD3DSurface *dst_surface, const POINT *dst_point)
5282 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5283 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5285 const struct wined3d_format *src_format;
5286 const struct wined3d_format *dst_format;
5287 const struct wined3d_gl_info *gl_info;
5288 struct wined3d_context *context;
5289 const unsigned char *data;
5290 UINT update_w, update_h;
5291 CONVERT_TYPES convert;
5292 UINT src_w, src_h;
5293 UINT dst_x, dst_y;
5294 DWORD sampler;
5295 struct wined3d_format format;
5297 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5298 iface, src_surface, wine_dbgstr_rect(src_rect),
5299 dst_surface, wine_dbgstr_point(dst_point));
5301 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5303 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5304 src_surface, dst_surface);
5305 return WINED3DERR_INVALIDCALL;
5308 src_format = src_impl->resource.format;
5309 dst_format = dst_impl->resource.format;
5311 if (src_format->id != dst_format->id)
5313 WARN("Source and destination surfaces should have the same format.\n");
5314 return WINED3DERR_INVALIDCALL;
5317 dst_x = dst_point ? dst_point->x : 0;
5318 dst_y = dst_point ? dst_point->y : 0;
5320 /* This call loads the OpenGL surface directly, instead of copying the
5321 * surface to the destination's sysmem copy. If surface conversion is
5322 * needed, use BltFast instead to copy in sysmem and use regular surface
5323 * loading. */
5324 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &format, &convert);
5325 if (convert != NO_CONVERSION || format.convert)
5326 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5328 context = context_acquire(This, NULL);
5329 gl_info = context->gl_info;
5331 ENTER_GL();
5332 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5333 checkGLcall("glActiveTextureARB");
5334 LEAVE_GL();
5336 /* Make sure the surface is loaded and up to date */
5337 surface_internal_preload(dst_impl, SRGB_RGB);
5338 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5340 src_w = src_impl->currentDesc.Width;
5341 src_h = src_impl->currentDesc.Height;
5342 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5343 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5345 data = IWineD3DSurface_GetData(src_surface);
5346 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5348 ENTER_GL();
5350 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5352 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5353 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5354 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5356 if (src_rect)
5358 data += (src_rect->top / src_format->block_height) * src_pitch;
5359 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5362 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5363 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5364 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5366 if (row_length == src_pitch)
5368 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5369 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5371 else
5373 UINT row, y;
5375 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5376 * can't use the unpack row length like below. */
5377 for (row = 0, y = dst_y; row < row_count; ++row)
5379 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5380 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5381 y += src_format->block_height;
5382 data += src_pitch;
5385 checkGLcall("glCompressedTexSubImage2DARB");
5387 else
5389 if (src_rect)
5391 data += src_rect->top * src_w * src_format->byte_count;
5392 data += src_rect->left * src_format->byte_count;
5395 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5396 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5397 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5399 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5400 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5401 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5402 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5403 checkGLcall("glTexSubImage2D");
5406 LEAVE_GL();
5407 context_release(context);
5409 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5410 sampler = This->rev_tex_unit_map[0];
5411 if (sampler != WINED3D_UNMAPPED_STAGE)
5413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5416 return WINED3D_OK;
5419 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5421 struct WineD3DRectPatch *patch;
5422 GLenum old_primitive_type;
5423 unsigned int i;
5424 struct list *e;
5425 BOOL found;
5426 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5428 if(!(Handle || pRectPatchInfo)) {
5429 /* TODO: Write a test for the return value, thus the FIXME */
5430 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5431 return WINED3DERR_INVALIDCALL;
5434 if(Handle) {
5435 i = PATCHMAP_HASHFUNC(Handle);
5436 found = FALSE;
5437 LIST_FOR_EACH(e, &This->patches[i]) {
5438 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5439 if(patch->Handle == Handle) {
5440 found = TRUE;
5441 break;
5445 if(!found) {
5446 TRACE("Patch does not exist. Creating a new one\n");
5447 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5448 patch->Handle = Handle;
5449 list_add_head(&This->patches[i], &patch->entry);
5450 } else {
5451 TRACE("Found existing patch %p\n", patch);
5453 } else {
5454 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5455 * attributes we have to tesselate, read back, and draw. This needs a patch
5456 * management structure instance. Create one.
5458 * A possible improvement is to check if a vertex shader is used, and if not directly
5459 * draw the patch.
5461 FIXME("Drawing an uncached patch. This is slow\n");
5462 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5465 if (pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1]
5466 || pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3]
5467 || (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo))))
5469 HRESULT hr;
5470 TRACE("Tesselation density or patch info changed, retesselating\n");
5472 if(pRectPatchInfo) {
5473 patch->RectPatchInfo = *pRectPatchInfo;
5475 patch->numSegs[0] = pNumSegs[0];
5476 patch->numSegs[1] = pNumSegs[1];
5477 patch->numSegs[2] = pNumSegs[2];
5478 patch->numSegs[3] = pNumSegs[3];
5480 hr = tesselate_rectpatch(This, patch);
5481 if(FAILED(hr)) {
5482 WARN("Patch tesselation failed\n");
5484 /* Do not release the handle to store the params of the patch */
5485 if(!Handle) {
5486 HeapFree(GetProcessHeap(), 0, patch);
5488 return hr;
5492 This->currentPatch = patch;
5493 old_primitive_type = This->stateBlock->gl_primitive_type;
5494 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5495 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5496 This->stateBlock->gl_primitive_type = old_primitive_type;
5497 This->currentPatch = NULL;
5499 /* Destroy uncached patches */
5500 if(!Handle) {
5501 HeapFree(GetProcessHeap(), 0, patch->mem);
5502 HeapFree(GetProcessHeap(), 0, patch);
5504 return WINED3D_OK;
5507 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5508 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5510 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5511 iface, handle, segment_count, patch_info);
5513 return WINED3D_OK;
5516 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5518 int i;
5519 struct WineD3DRectPatch *patch;
5520 struct list *e;
5521 TRACE("(%p) Handle(%d)\n", This, Handle);
5523 i = PATCHMAP_HASHFUNC(Handle);
5524 LIST_FOR_EACH(e, &This->patches[i]) {
5525 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5526 if(patch->Handle == Handle) {
5527 TRACE("Deleting patch %p\n", patch);
5528 list_remove(&patch->entry);
5529 HeapFree(GetProcessHeap(), 0, patch->mem);
5530 HeapFree(GetProcessHeap(), 0, patch);
5531 return WINED3D_OK;
5535 /* TODO: Write a test for the return value */
5536 FIXME("Attempt to destroy nonexistent patch\n");
5537 return WINED3DERR_INVALIDCALL;
5540 /* Do not call while under the GL lock. */
5541 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5542 IWineD3DSurface *surface, const RECT *rect, const WINED3DCOLORVALUE *color)
5544 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5546 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5547 iface, surface, wine_dbgstr_rect(rect),
5548 color->r, color->g, color->b, color->a);
5550 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5552 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5553 return WINED3DERR_INVALIDCALL;
5556 return surface_color_fill(s, rect, color);
5559 /* Do not call while under the GL lock. */
5560 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5561 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5563 IWineD3DResource *resource;
5564 HRESULT hr;
5566 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5567 if (FAILED(hr))
5569 ERR("Failed to get resource, hr %#x\n", hr);
5570 return;
5573 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5575 FIXME("Only supported on surface resources\n");
5576 IWineD3DResource_Release(resource);
5577 return;
5580 hr = surface_color_fill((IWineD3DSurfaceImpl *)resource, NULL, color);
5581 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
5583 IWineD3DResource_Release(resource);
5586 /* rendertarget and depth stencil functions */
5587 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5588 DWORD render_target_idx, IWineD3DSurface **render_target)
5590 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5592 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5593 iface, render_target_idx, render_target);
5595 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5597 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5598 return WINED3DERR_INVALIDCALL;
5601 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5602 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5604 TRACE("Returning render target %p.\n", *render_target);
5606 return WINED3D_OK;
5609 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5610 IWineD3DSurface *front, IWineD3DSurface *back)
5612 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5613 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5614 IWineD3DSwapChainImpl *swapchain;
5615 HRESULT hr;
5617 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5619 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5621 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5622 return hr;
5625 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5627 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5628 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5629 return WINED3DERR_INVALIDCALL;
5632 if (back_impl)
5634 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5636 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5637 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5638 return WINED3DERR_INVALIDCALL;
5641 if (!swapchain->back_buffers)
5643 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5644 if (!swapchain->back_buffers)
5646 ERR("Failed to allocate back buffer array memory.\n");
5647 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5648 return E_OUTOFMEMORY;
5653 if (swapchain->front_buffer != front_impl)
5655 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5657 if (swapchain->front_buffer)
5658 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5659 swapchain->front_buffer = front_impl;
5661 if (front_impl)
5662 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5665 if (swapchain->back_buffers[0] != back_impl)
5667 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5669 if (swapchain->back_buffers[0])
5670 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5671 swapchain->back_buffers[0] = back_impl;
5673 if (back_impl)
5675 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5676 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5677 swapchain->presentParms.BackBufferFormat = back_impl->resource.format->id;
5678 swapchain->presentParms.BackBufferCount = 1;
5680 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5682 else
5684 swapchain->presentParms.BackBufferCount = 0;
5685 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5686 swapchain->back_buffers = NULL;
5690 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5691 return WINED3D_OK;
5694 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5696 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5698 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5700 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5701 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5702 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5703 IWineD3DSurface_AddRef(*depth_stencil);
5705 return WINED3D_OK;
5708 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5709 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5711 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5712 IWineD3DSurfaceImpl *prev;
5714 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5715 iface, render_target_idx, render_target, set_viewport);
5717 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5719 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5720 return WINED3DERR_INVALIDCALL;
5723 prev = device->render_targets[render_target_idx];
5724 if (render_target == (IWineD3DSurface *)prev)
5726 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5727 return WINED3D_OK;
5730 /* Render target 0 can't be set to NULL. */
5731 if (!render_target && !render_target_idx)
5733 WARN("Trying to set render target 0 to NULL.\n");
5734 return WINED3DERR_INVALIDCALL;
5737 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5739 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5740 return WINED3DERR_INVALIDCALL;
5743 if (render_target) IWineD3DSurface_AddRef(render_target);
5744 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5745 /* Release after the assignment, to prevent device_resource_released()
5746 * from seeing the surface as still in use. */
5747 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5749 /* Render target 0 is special. */
5750 if (!render_target_idx && set_viewport)
5752 /* Set the viewport and scissor rectangles, if requested. Tests show
5753 * that stateblock recording is ignored, the change goes directly
5754 * into the primary stateblock. */
5755 device->stateBlock->state.viewport.Height = device->render_targets[0]->currentDesc.Height;
5756 device->stateBlock->state.viewport.Width = device->render_targets[0]->currentDesc.Width;
5757 device->stateBlock->state.viewport.X = 0;
5758 device->stateBlock->state.viewport.Y = 0;
5759 device->stateBlock->state.viewport.MaxZ = 1.0f;
5760 device->stateBlock->state.viewport.MinZ = 0.0f;
5761 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5763 device->stateBlock->state.scissor_rect.top = 0;
5764 device->stateBlock->state.scissor_rect.left = 0;
5765 device->stateBlock->state.scissor_rect.right = device->stateBlock->state.viewport.Width;
5766 device->stateBlock->state.scissor_rect.bottom = device->stateBlock->state.viewport.Height;
5767 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5770 return WINED3D_OK;
5773 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 IWineD3DSurfaceImpl *tmp;
5778 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5780 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5782 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5783 return WINED3D_OK;
5786 if (This->depth_stencil)
5788 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5789 || This->depth_stencil->Flags & SFLAG_DISCARD)
5791 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5792 This->depth_stencil->currentDesc.Width,
5793 This->depth_stencil->currentDesc.Height);
5794 if (This->depth_stencil == This->onscreen_depth_stencil)
5796 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5797 This->onscreen_depth_stencil = NULL;
5802 tmp = This->depth_stencil;
5803 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5804 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5805 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5807 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5809 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5815 return WINED3D_OK;
5818 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5819 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5823 WINED3DLOCKED_RECT lockedRect;
5825 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5826 iface, XHotSpot, YHotSpot, cursor_image);
5828 /* some basic validation checks */
5829 if (This->cursorTexture)
5831 struct wined3d_context *context = context_acquire(This, NULL);
5832 ENTER_GL();
5833 glDeleteTextures(1, &This->cursorTexture);
5834 LEAVE_GL();
5835 context_release(context);
5836 This->cursorTexture = 0;
5839 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5840 This->haveHardwareCursor = TRUE;
5841 else
5842 This->haveHardwareCursor = FALSE;
5844 if (cursor_image)
5846 WINED3DLOCKED_RECT rect;
5848 /* MSDN: Cursor must be A8R8G8B8 */
5849 if (s->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
5851 WARN("surface %p has an invalid format.\n", cursor_image);
5852 return WINED3DERR_INVALIDCALL;
5855 /* MSDN: Cursor must be smaller than the display mode */
5856 if (s->currentDesc.Width > This->ddraw_width
5857 || s->currentDesc.Height > This->ddraw_height)
5859 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5860 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5861 return WINED3DERR_INVALIDCALL;
5864 if (!This->haveHardwareCursor) {
5865 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5867 /* Do not store the surface's pointer because the application may
5868 * release it after setting the cursor image. Windows doesn't
5869 * addref the set surface, so we can't do this either without
5870 * creating circular refcount dependencies. Copy out the gl texture
5871 * instead.
5873 This->cursorWidth = s->currentDesc.Width;
5874 This->cursorHeight = s->currentDesc.Height;
5875 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5877 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5878 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
5879 struct wined3d_context *context;
5880 char *mem, *bits = rect.pBits;
5881 GLint intfmt = format->glInternal;
5882 GLint gl_format = format->glFormat;
5883 GLint type = format->glType;
5884 INT height = This->cursorHeight;
5885 INT width = This->cursorWidth;
5886 INT bpp = format->byte_count;
5887 DWORD sampler;
5888 INT i;
5890 /* Reformat the texture memory (pitch and width can be
5891 * different) */
5892 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5893 for(i = 0; i < height; i++)
5894 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5895 IWineD3DSurface_UnlockRect(cursor_image);
5897 context = context_acquire(This, NULL);
5899 ENTER_GL();
5901 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5903 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5904 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5907 /* Make sure that a proper texture unit is selected */
5908 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5909 checkGLcall("glActiveTextureARB");
5910 sampler = This->rev_tex_unit_map[0];
5911 if (sampler != WINED3D_UNMAPPED_STAGE)
5913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5915 /* Create a new cursor texture */
5916 glGenTextures(1, &This->cursorTexture);
5917 checkGLcall("glGenTextures");
5918 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5919 checkGLcall("glBindTexture");
5920 /* Copy the bitmap memory into the cursor texture */
5921 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
5922 HeapFree(GetProcessHeap(), 0, mem);
5923 checkGLcall("glTexImage2D");
5925 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5927 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5928 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5931 LEAVE_GL();
5933 context_release(context);
5935 else
5937 FIXME("A cursor texture was not returned.\n");
5938 This->cursorTexture = 0;
5941 else
5943 /* Draw a hardware cursor */
5944 ICONINFO cursorInfo;
5945 HCURSOR cursor;
5946 /* Create and clear maskBits because it is not needed for
5947 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5948 * chunks. */
5949 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5950 (s->currentDesc.Width * s->currentDesc.Height / 8));
5951 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5952 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5953 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5955 cursorInfo.fIcon = FALSE;
5956 cursorInfo.xHotspot = XHotSpot;
5957 cursorInfo.yHotspot = YHotSpot;
5958 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5959 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5960 IWineD3DSurface_UnlockRect(cursor_image);
5961 /* Create our cursor and clean up. */
5962 cursor = CreateIconIndirect(&cursorInfo);
5963 SetCursor(cursor);
5964 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5965 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5966 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5967 This->hardwareCursor = cursor;
5968 HeapFree(GetProcessHeap(), 0, maskBits);
5972 This->xHotSpot = XHotSpot;
5973 This->yHotSpot = YHotSpot;
5974 return WINED3D_OK;
5977 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5979 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5981 This->xScreenSpace = XScreenSpace;
5982 This->yScreenSpace = YScreenSpace;
5984 return;
5988 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5990 BOOL oldVisible = This->bCursorVisible;
5991 POINT pt;
5993 TRACE("(%p) : visible(%d)\n", This, bShow);
5996 * When ShowCursor is first called it should make the cursor appear at the OS's last
5997 * known cursor position. Because of this, some applications just repetitively call
5998 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6000 GetCursorPos(&pt);
6001 This->xScreenSpace = pt.x;
6002 This->yScreenSpace = pt.y;
6004 if (This->haveHardwareCursor) {
6005 This->bCursorVisible = bShow;
6006 if (bShow)
6007 SetCursor(This->hardwareCursor);
6008 else
6009 SetCursor(NULL);
6011 else
6013 if (This->cursorTexture)
6014 This->bCursorVisible = bShow;
6017 return oldVisible;
6020 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6021 TRACE("checking resource %p for eviction\n", resource);
6022 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6023 TRACE("Evicting %p\n", resource);
6024 IWineD3DResource_UnLoad(resource);
6026 IWineD3DResource_Release(resource);
6027 return S_OK;
6030 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6032 TRACE("iface %p.\n", iface);
6034 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6035 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6036 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6038 return WINED3D_OK;
6041 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6043 IWineD3DDeviceImpl *device = surface->resource.device;
6044 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6046 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6047 if(surface->Flags & SFLAG_DIBSECTION) {
6048 /* Release the DC */
6049 SelectObject(surface->hDC, surface->dib.holdbitmap);
6050 DeleteDC(surface->hDC);
6051 /* Release the DIB section */
6052 DeleteObject(surface->dib.DIBsection);
6053 surface->dib.bitmap_data = NULL;
6054 surface->resource.allocatedMemory = NULL;
6055 surface->Flags &= ~SFLAG_DIBSECTION;
6057 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6058 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6059 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6060 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6062 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6063 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6064 } else {
6065 surface->pow2Width = surface->pow2Height = 1;
6066 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6067 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6070 if (surface->texture_name)
6072 struct wined3d_context *context = context_acquire(device, NULL);
6073 ENTER_GL();
6074 glDeleteTextures(1, &surface->texture_name);
6075 LEAVE_GL();
6076 context_release(context);
6077 surface->texture_name = 0;
6078 surface->Flags &= ~SFLAG_CLIENT;
6080 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6081 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6082 surface->Flags |= SFLAG_NONPOW2;
6083 } else {
6084 surface->Flags &= ~SFLAG_NONPOW2;
6086 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6087 surface->resource.allocatedMemory = NULL;
6088 surface->resource.heapMemory = NULL;
6089 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6091 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6092 * to a FBO */
6093 if (!surface_init_sysmem(surface))
6095 return E_OUTOFMEMORY;
6097 return WINED3D_OK;
6100 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6101 TRACE("Unloading resource %p\n", resource);
6102 IWineD3DResource_UnLoad(resource);
6103 IWineD3DResource_Release(resource);
6104 return S_OK;
6107 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6109 UINT i, count;
6110 WINED3DDISPLAYMODE m;
6111 HRESULT hr;
6113 /* All Windowed modes are supported, as is leaving the current mode */
6114 if(pp->Windowed) return TRUE;
6115 if(!pp->BackBufferWidth) return TRUE;
6116 if(!pp->BackBufferHeight) return TRUE;
6118 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6119 for(i = 0; i < count; i++) {
6120 memset(&m, 0, sizeof(m));
6121 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6122 if(FAILED(hr)) {
6123 ERR("EnumAdapterModes failed\n");
6125 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6126 /* Mode found, it is supported */
6127 return TRUE;
6130 /* Mode not found -> not supported */
6131 return FALSE;
6134 /* Do not call while under the GL lock. */
6135 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6138 const struct wined3d_gl_info *gl_info;
6139 struct wined3d_context *context;
6140 IWineD3DBaseShaderImpl *shader;
6142 context = context_acquire(This, NULL);
6143 gl_info = context->gl_info;
6145 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6146 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6147 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6150 ENTER_GL();
6151 if(This->depth_blt_texture) {
6152 glDeleteTextures(1, &This->depth_blt_texture);
6153 This->depth_blt_texture = 0;
6155 if (This->depth_blt_rb) {
6156 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6157 This->depth_blt_rb = 0;
6158 This->depth_blt_rb_w = 0;
6159 This->depth_blt_rb_h = 0;
6161 LEAVE_GL();
6163 This->blitter->free_private(iface);
6164 This->frag_pipe->free_private(iface);
6165 This->shader_backend->shader_free_private(iface);
6166 destroy_dummy_textures(This, gl_info);
6168 context_release(context);
6170 while (This->numContexts)
6172 context_destroy(This, This->contexts[0]);
6174 HeapFree(GetProcessHeap(), 0, swapchain->context);
6175 swapchain->context = NULL;
6176 swapchain->num_contexts = 0;
6179 /* Do not call while under the GL lock. */
6180 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6183 struct wined3d_context *context;
6184 HRESULT hr;
6185 IWineD3DSurfaceImpl *target;
6187 /* Recreate the primary swapchain's context */
6188 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6189 if (!swapchain->context)
6191 ERR("Failed to allocate memory for swapchain context array.\n");
6192 return E_OUTOFMEMORY;
6195 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6196 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6198 WARN("Failed to create context.\n");
6199 HeapFree(GetProcessHeap(), 0, swapchain->context);
6200 return E_FAIL;
6203 swapchain->context[0] = context;
6204 swapchain->num_contexts = 1;
6205 create_dummy_textures(This);
6206 context_release(context);
6208 hr = This->shader_backend->shader_alloc_private(iface);
6209 if (FAILED(hr))
6211 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6212 goto err;
6215 hr = This->frag_pipe->alloc_private(iface);
6216 if (FAILED(hr))
6218 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6219 This->shader_backend->shader_free_private(iface);
6220 goto err;
6223 hr = This->blitter->alloc_private(iface);
6224 if (FAILED(hr))
6226 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6227 This->frag_pipe->free_private(iface);
6228 This->shader_backend->shader_free_private(iface);
6229 goto err;
6232 return WINED3D_OK;
6234 err:
6235 context_acquire(This, NULL);
6236 destroy_dummy_textures(This, context->gl_info);
6237 context_release(context);
6238 context_destroy(This, context);
6239 HeapFree(GetProcessHeap(), 0, swapchain->context);
6240 swapchain->num_contexts = 0;
6241 return hr;
6244 /* Do not call while under the GL lock. */
6245 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice *iface,
6246 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6249 IWineD3DSwapChainImpl *swapchain;
6250 HRESULT hr;
6251 BOOL DisplayModeChanged = FALSE;
6252 WINED3DDISPLAYMODE mode;
6253 TRACE("(%p)\n", This);
6255 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6256 if(FAILED(hr)) {
6257 ERR("Failed to get the first implicit swapchain\n");
6258 return hr;
6261 if(!is_display_mode_supported(This, pPresentationParameters)) {
6262 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6263 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6264 pPresentationParameters->BackBufferHeight);
6265 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6266 return WINED3DERR_INVALIDCALL;
6269 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6270 * on an existing gl context, so there's no real need for recreation.
6272 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6274 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6276 TRACE("New params:\n");
6277 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6278 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6279 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6280 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6281 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6282 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6283 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6284 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6285 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6286 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6287 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6288 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6289 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6291 /* No special treatment of these parameters. Just store them */
6292 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6293 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6294 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6295 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6297 /* What to do about these? */
6298 if (pPresentationParameters->BackBufferCount
6299 && pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount)
6300 ERR("Cannot change the back buffer count yet\n");
6302 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6303 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6304 ERR("Cannot change the back buffer format yet\n");
6307 if (pPresentationParameters->hDeviceWindow
6308 && pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow)
6309 ERR("Cannot change the device window yet\n");
6311 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6313 HRESULT hrc;
6315 TRACE("Creating the depth stencil buffer\n");
6317 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6318 pPresentationParameters->BackBufferWidth,
6319 pPresentationParameters->BackBufferHeight,
6320 pPresentationParameters->AutoDepthStencilFormat,
6321 pPresentationParameters->MultiSampleType,
6322 pPresentationParameters->MultiSampleQuality,
6323 FALSE,
6324 (IWineD3DSurface **)&This->auto_depth_stencil);
6326 if (FAILED(hrc)) {
6327 ERR("Failed to create the depth stencil buffer\n");
6328 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6329 return WINED3DERR_INVALIDCALL;
6333 if (This->onscreen_depth_stencil)
6335 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6336 This->onscreen_depth_stencil = NULL;
6339 /* Reset the depth stencil */
6340 if (pPresentationParameters->EnableAutoDepthStencil)
6341 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6342 else
6343 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6345 TRACE("Resetting stateblock\n");
6346 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6347 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6349 delete_opengl_contexts(iface, swapchain);
6351 if(pPresentationParameters->Windowed) {
6352 mode.Width = swapchain->orig_width;
6353 mode.Height = swapchain->orig_height;
6354 mode.RefreshRate = 0;
6355 mode.Format = swapchain->presentParms.BackBufferFormat;
6356 } else {
6357 mode.Width = pPresentationParameters->BackBufferWidth;
6358 mode.Height = pPresentationParameters->BackBufferHeight;
6359 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6360 mode.Format = swapchain->presentParms.BackBufferFormat;
6363 /* Should Width == 800 && Height == 0 set 800x600? */
6364 if (pPresentationParameters->BackBufferWidth && pPresentationParameters->BackBufferHeight
6365 && (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth
6366 || pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6368 UINT i;
6370 if(!pPresentationParameters->Windowed) {
6371 DisplayModeChanged = TRUE;
6373 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6374 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6376 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6377 if(FAILED(hr))
6379 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6380 return hr;
6383 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6385 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6386 if(FAILED(hr))
6388 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6389 return hr;
6392 if (This->auto_depth_stencil)
6394 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6395 if(FAILED(hr))
6397 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6398 return hr;
6403 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6404 || DisplayModeChanged)
6406 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6408 if (!pPresentationParameters->Windowed)
6410 if(swapchain->presentParms.Windowed) {
6411 /* switch from windowed to fs */
6412 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6413 pPresentationParameters->BackBufferHeight);
6414 } else {
6415 /* Fullscreen -> fullscreen mode change */
6416 MoveWindow(swapchain->device_window, 0, 0,
6417 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6418 TRUE);
6421 else if (!swapchain->presentParms.Windowed)
6423 /* Fullscreen -> windowed switch */
6424 swapchain_restore_fullscreen_window(swapchain);
6426 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6427 } else if(!pPresentationParameters->Windowed) {
6428 DWORD style = This->style, exStyle = This->exStyle;
6429 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6430 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6431 * Reset to clear up their mess. Guild Wars also loses the device during that.
6433 This->style = 0;
6434 This->exStyle = 0;
6435 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6436 pPresentationParameters->BackBufferHeight);
6437 This->style = style;
6438 This->exStyle = exStyle;
6441 /* Note: No parent needed for initial internal stateblock */
6442 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6443 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6444 else TRACE("Created stateblock %p\n", This->stateBlock);
6445 This->updateStateBlock = This->stateBlock;
6446 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6448 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6449 if(FAILED(hr)) {
6450 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6453 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6455 RECT client_rect;
6456 GetClientRect(swapchain->win_handle, &client_rect);
6458 if(!swapchain->presentParms.BackBufferCount)
6460 TRACE("Single buffered rendering\n");
6461 swapchain->render_to_fbo = FALSE;
6463 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6464 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6466 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6467 swapchain->presentParms.BackBufferWidth,
6468 swapchain->presentParms.BackBufferHeight,
6469 client_rect.right, client_rect.bottom);
6470 swapchain->render_to_fbo = TRUE;
6472 else
6474 TRACE("Rendering directly to GL_BACK\n");
6475 swapchain->render_to_fbo = FALSE;
6479 hr = create_primary_opengl_context(iface, swapchain);
6480 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6482 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6483 * first use
6485 return hr;
6488 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6490 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6492 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6494 return WINED3D_OK;
6498 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6500 TRACE("(%p) : pParameters %p\n", This, pParameters);
6502 *pParameters = This->createParms;
6503 return WINED3D_OK;
6506 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6507 IWineD3DSwapChain *swapchain;
6509 TRACE("Relaying to swapchain\n");
6511 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6512 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6513 IWineD3DSwapChain_Release(swapchain);
6517 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6518 IWineD3DSwapChain *swapchain;
6520 TRACE("Relaying to swapchain\n");
6522 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6523 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6524 IWineD3DSwapChain_Release(swapchain);
6529 /** ********************************************************
6530 * Notification functions
6531 ** ********************************************************/
6532 /** This function must be called in the release of a resource when ref == 0,
6533 * the contents of resource must still be correct,
6534 * any handles to other resource held by the caller must be closed
6535 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6536 *****************************************************/
6537 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6539 TRACE("(%p) : Adding resource %p\n", This, resource);
6541 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6544 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6546 TRACE("(%p) : Removing resource %p\n", This, resource);
6548 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6551 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6553 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6554 unsigned int i;
6556 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6558 context_resource_released(device, resource, type);
6560 switch (type)
6562 case WINED3DRTYPE_SURFACE:
6563 if (!device->d3d_initialized) break;
6565 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6567 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6569 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6570 device->render_targets[i] = NULL;
6574 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6576 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6577 device->depth_stencil = NULL;
6579 break;
6581 case WINED3DRTYPE_TEXTURE:
6582 case WINED3DRTYPE_CUBETEXTURE:
6583 case WINED3DRTYPE_VOLUMETEXTURE:
6584 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6586 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6588 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6589 resource, device->stateBlock, i);
6590 device->stateBlock->textures[i] = NULL;
6593 if (device->updateStateBlock != device->stateBlock
6594 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6596 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6597 resource, device->updateStateBlock, i);
6598 device->updateStateBlock->textures[i] = NULL;
6601 break;
6603 case WINED3DRTYPE_BUFFER:
6604 for (i = 0; i < MAX_STREAMS; ++i)
6606 if (device->stateBlock && device->stateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6608 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6609 resource, device->stateBlock, i);
6610 device->stateBlock->streams[i].buffer = NULL;
6613 if (device->updateStateBlock != device->stateBlock
6614 && device->updateStateBlock->streams[i].buffer == (struct wined3d_buffer *)resource)
6616 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6617 resource, device->updateStateBlock, i);
6618 device->updateStateBlock->streams[i].buffer = NULL;
6623 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6625 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6626 resource, device->stateBlock);
6627 device->stateBlock->pIndexData = NULL;
6630 if (device->updateStateBlock != device->stateBlock
6631 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6633 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6634 resource, device->updateStateBlock);
6635 device->updateStateBlock->pIndexData = NULL;
6637 break;
6639 default:
6640 break;
6643 /* Remove the resource from the resourceStore */
6644 device_resource_remove(device, resource);
6646 TRACE("Resource released.\n");
6649 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6651 IWineD3DResourceImpl *resource, *cursor;
6652 HRESULT ret;
6653 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6655 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6656 TRACE("enumerating resource %p\n", resource);
6657 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6658 ret = pCallback((IWineD3DResource *) resource, pData);
6659 if(ret == S_FALSE) {
6660 TRACE("Canceling enumeration\n");
6661 break;
6664 return WINED3D_OK;
6667 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6670 IWineD3DResourceImpl *resource;
6672 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6674 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6675 if (type == WINED3DRTYPE_SURFACE)
6677 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6679 TRACE("Found surface %p for dc %p.\n", resource, dc);
6680 *surface = (IWineD3DSurface *)resource;
6681 return WINED3D_OK;
6686 return WINED3DERR_INVALIDCALL;
6689 /**********************************************************
6690 * IWineD3DDevice VTbl follows
6691 **********************************************************/
6693 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6695 /*** IUnknown methods ***/
6696 IWineD3DDeviceImpl_QueryInterface,
6697 IWineD3DDeviceImpl_AddRef,
6698 IWineD3DDeviceImpl_Release,
6699 /*** IWineD3DDevice methods ***/
6700 /*** Creation methods**/
6701 IWineD3DDeviceImpl_CreateBuffer,
6702 IWineD3DDeviceImpl_CreateVertexBuffer,
6703 IWineD3DDeviceImpl_CreateIndexBuffer,
6704 IWineD3DDeviceImpl_CreateStateBlock,
6705 IWineD3DDeviceImpl_CreateSurface,
6706 IWineD3DDeviceImpl_CreateRendertargetView,
6707 IWineD3DDeviceImpl_CreateTexture,
6708 IWineD3DDeviceImpl_CreateVolumeTexture,
6709 IWineD3DDeviceImpl_CreateVolume,
6710 IWineD3DDeviceImpl_CreateCubeTexture,
6711 IWineD3DDeviceImpl_CreateQuery,
6712 IWineD3DDeviceImpl_CreateSwapChain,
6713 IWineD3DDeviceImpl_CreateVertexDeclaration,
6714 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6715 IWineD3DDeviceImpl_CreateVertexShader,
6716 IWineD3DDeviceImpl_CreateGeometryShader,
6717 IWineD3DDeviceImpl_CreatePixelShader,
6718 IWineD3DDeviceImpl_CreatePalette,
6719 /*** Odd functions **/
6720 IWineD3DDeviceImpl_Init3D,
6721 IWineD3DDeviceImpl_InitGDI,
6722 IWineD3DDeviceImpl_Uninit3D,
6723 IWineD3DDeviceImpl_UninitGDI,
6724 IWineD3DDeviceImpl_SetMultithreaded,
6725 IWineD3DDeviceImpl_EvictManagedResources,
6726 IWineD3DDeviceImpl_GetAvailableTextureMem,
6727 IWineD3DDeviceImpl_GetBackBuffer,
6728 IWineD3DDeviceImpl_GetCreationParameters,
6729 IWineD3DDeviceImpl_GetDeviceCaps,
6730 IWineD3DDeviceImpl_GetDirect3D,
6731 IWineD3DDeviceImpl_GetDisplayMode,
6732 IWineD3DDeviceImpl_SetDisplayMode,
6733 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6734 IWineD3DDeviceImpl_GetRasterStatus,
6735 IWineD3DDeviceImpl_GetSwapChain,
6736 IWineD3DDeviceImpl_Reset,
6737 IWineD3DDeviceImpl_SetDialogBoxMode,
6738 IWineD3DDeviceImpl_SetCursorProperties,
6739 IWineD3DDeviceImpl_SetCursorPosition,
6740 IWineD3DDeviceImpl_ShowCursor,
6741 /*** Getters and setters **/
6742 IWineD3DDeviceImpl_SetClipPlane,
6743 IWineD3DDeviceImpl_GetClipPlane,
6744 IWineD3DDeviceImpl_SetClipStatus,
6745 IWineD3DDeviceImpl_GetClipStatus,
6746 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6747 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6748 IWineD3DDeviceImpl_SetDepthStencilSurface,
6749 IWineD3DDeviceImpl_GetDepthStencilSurface,
6750 IWineD3DDeviceImpl_SetGammaRamp,
6751 IWineD3DDeviceImpl_GetGammaRamp,
6752 IWineD3DDeviceImpl_SetIndexBuffer,
6753 IWineD3DDeviceImpl_GetIndexBuffer,
6754 IWineD3DDeviceImpl_SetBaseVertexIndex,
6755 IWineD3DDeviceImpl_GetBaseVertexIndex,
6756 IWineD3DDeviceImpl_SetLight,
6757 IWineD3DDeviceImpl_GetLight,
6758 IWineD3DDeviceImpl_SetLightEnable,
6759 IWineD3DDeviceImpl_GetLightEnable,
6760 IWineD3DDeviceImpl_SetMaterial,
6761 IWineD3DDeviceImpl_GetMaterial,
6762 IWineD3DDeviceImpl_SetNPatchMode,
6763 IWineD3DDeviceImpl_GetNPatchMode,
6764 IWineD3DDeviceImpl_SetPaletteEntries,
6765 IWineD3DDeviceImpl_GetPaletteEntries,
6766 IWineD3DDeviceImpl_SetPixelShader,
6767 IWineD3DDeviceImpl_GetPixelShader,
6768 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6769 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6770 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6771 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6772 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6773 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6774 IWineD3DDeviceImpl_SetRenderState,
6775 IWineD3DDeviceImpl_GetRenderState,
6776 IWineD3DDeviceImpl_SetRenderTarget,
6777 IWineD3DDeviceImpl_GetRenderTarget,
6778 IWineD3DDeviceImpl_SetFrontBackBuffers,
6779 IWineD3DDeviceImpl_SetSamplerState,
6780 IWineD3DDeviceImpl_GetSamplerState,
6781 IWineD3DDeviceImpl_SetScissorRect,
6782 IWineD3DDeviceImpl_GetScissorRect,
6783 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6784 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6785 IWineD3DDeviceImpl_SetStreamSource,
6786 IWineD3DDeviceImpl_GetStreamSource,
6787 IWineD3DDeviceImpl_SetStreamSourceFreq,
6788 IWineD3DDeviceImpl_GetStreamSourceFreq,
6789 IWineD3DDeviceImpl_SetTexture,
6790 IWineD3DDeviceImpl_GetTexture,
6791 IWineD3DDeviceImpl_SetTextureStageState,
6792 IWineD3DDeviceImpl_GetTextureStageState,
6793 IWineD3DDeviceImpl_SetTransform,
6794 IWineD3DDeviceImpl_GetTransform,
6795 IWineD3DDeviceImpl_SetVertexDeclaration,
6796 IWineD3DDeviceImpl_GetVertexDeclaration,
6797 IWineD3DDeviceImpl_SetVertexShader,
6798 IWineD3DDeviceImpl_GetVertexShader,
6799 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6800 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6801 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6802 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6803 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6804 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6805 IWineD3DDeviceImpl_SetViewport,
6806 IWineD3DDeviceImpl_GetViewport,
6807 IWineD3DDeviceImpl_MultiplyTransform,
6808 IWineD3DDeviceImpl_ValidateDevice,
6809 IWineD3DDeviceImpl_ProcessVertices,
6810 /*** State block ***/
6811 IWineD3DDeviceImpl_BeginStateBlock,
6812 IWineD3DDeviceImpl_EndStateBlock,
6813 /*** Scene management ***/
6814 IWineD3DDeviceImpl_BeginScene,
6815 IWineD3DDeviceImpl_EndScene,
6816 IWineD3DDeviceImpl_Present,
6817 IWineD3DDeviceImpl_Clear,
6818 IWineD3DDeviceImpl_ClearRendertargetView,
6819 /*** Drawing ***/
6820 IWineD3DDeviceImpl_SetPrimitiveType,
6821 IWineD3DDeviceImpl_GetPrimitiveType,
6822 IWineD3DDeviceImpl_DrawPrimitive,
6823 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6824 IWineD3DDeviceImpl_DrawPrimitiveUP,
6825 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6826 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6827 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6828 IWineD3DDeviceImpl_DrawRectPatch,
6829 IWineD3DDeviceImpl_DrawTriPatch,
6830 IWineD3DDeviceImpl_DeletePatch,
6831 IWineD3DDeviceImpl_ColorFill,
6832 IWineD3DDeviceImpl_UpdateTexture,
6833 IWineD3DDeviceImpl_UpdateSurface,
6834 IWineD3DDeviceImpl_GetFrontBufferData,
6835 /*** object tracking ***/
6836 IWineD3DDeviceImpl_EnumResources,
6837 IWineD3DDeviceImpl_GetSurfaceFromDC,
6838 IWineD3DDeviceImpl_AcquireFocusWindow,
6839 IWineD3DDeviceImpl_ReleaseFocusWindow,
6842 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6843 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6844 IWineD3DDeviceParent *device_parent)
6846 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6847 const struct fragment_pipeline *fragment_pipeline;
6848 struct shader_caps shader_caps;
6849 struct fragment_caps ffp_caps;
6850 WINED3DDISPLAYMODE mode;
6851 unsigned int i;
6852 HRESULT hr;
6854 device->lpVtbl = &IWineD3DDevice_Vtbl;
6855 device->ref = 1;
6856 device->wined3d = (IWineD3D *)wined3d;
6857 IWineD3D_AddRef(device->wined3d);
6858 device->adapter = wined3d->adapter_count ? adapter : NULL;
6859 device->device_parent = device_parent;
6860 list_init(&device->resources);
6861 list_init(&device->shaders);
6863 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6864 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6866 /* Get the initial screen setup for ddraw. */
6867 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6868 if (FAILED(hr))
6870 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6871 IWineD3D_Release(device->wined3d);
6872 return hr;
6874 device->ddraw_width = mode.Width;
6875 device->ddraw_height = mode.Height;
6876 device->ddraw_format = mode.Format;
6878 /* Save the creation parameters. */
6879 device->createParms.AdapterOrdinal = adapter_idx;
6880 device->createParms.DeviceType = device_type;
6881 device->createParms.hFocusWindow = focus_window;
6882 device->createParms.BehaviorFlags = flags;
6884 device->devType = device_type;
6885 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6887 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6888 device->shader_backend = adapter->shader_backend;
6890 if (device->shader_backend)
6892 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6893 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6894 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6895 device->vs_clipping = shader_caps.VSClipping;
6897 fragment_pipeline = adapter->fragment_pipe;
6898 device->frag_pipe = fragment_pipeline;
6899 if (fragment_pipeline)
6901 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6902 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6904 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6905 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6906 if (FAILED(hr))
6908 ERR("Failed to compile state table, hr %#x.\n", hr);
6909 IWineD3D_Release(device->wined3d);
6910 return hr;
6913 device->blitter = adapter->blitter;
6915 return WINED3D_OK;
6919 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6920 DWORD rep = This->StateTable[state].representative;
6921 struct wined3d_context *context;
6922 DWORD idx;
6923 BYTE shift;
6924 UINT i;
6926 for(i = 0; i < This->numContexts; i++) {
6927 context = This->contexts[i];
6928 if(isStateDirty(context, rep)) continue;
6930 context->dirtyArray[context->numDirtyEntries++] = rep;
6931 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6932 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6933 context->isStateDirty[idx] |= (1 << shift);
6937 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6939 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6940 *width = context->current_rt->pow2Width;
6941 *height = context->current_rt->pow2Height;
6944 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6946 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6947 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6948 * current context's drawable, which is the size of the back buffer of the swapchain
6949 * the active context belongs to. */
6950 *width = swapchain->presentParms.BackBufferWidth;
6951 *height = swapchain->presentParms.BackBufferHeight;
6954 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6955 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6957 if (device->filter_messages)
6959 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6960 window, message, wparam, lparam);
6961 return DefWindowProcW(window, message, wparam, lparam);
6964 if (message == WM_DESTROY)
6966 TRACE("unregister window %p.\n", window);
6967 wined3d_unregister_window(window);
6969 if (device->focus_window == window) device->focus_window = NULL;
6970 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6973 return CallWindowProcW(proc, window, message, wparam, lparam);