configure: Changes from running autconf after previous patch.
[wine/hacks.git] / dlls / wined3d / device.c
blobecd2919a2fc1a7e4e65cea237c0de1f86ede535c
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
181 unsigned int i;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 GLuint buffer_object = 0;
195 const BYTE *data = NULL;
196 BOOL stride_used;
197 unsigned int idx;
198 DWORD stride;
200 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201 element, i + 1, declaration->element_count);
203 if (!This->stateBlock->streamSource[element->input_slot]) continue;
205 stride = This->stateBlock->streamStride[element->input_slot];
206 if (This->stateBlock->streamIsUP)
208 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
209 buffer_object = 0;
210 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
212 else
214 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
215 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot],
216 &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
226 buffer_object = 0;
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot],
228 &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 warned = TRUE;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
278 stride_used = FALSE;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->streamIsUP)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
319 struct wined3d_event_query *query;
321 if (!(map & 1)) continue;
323 element = &stream_info->elements[i];
324 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
325 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
327 /* If PreLoad dropped the buffer object, update the stream info. */
328 if (buffer->buffer_object != element->buffer_object)
330 element->buffer_object = 0;
331 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 query = ((struct wined3d_buffer *) buffer)->query;
335 if(query)
337 This->buffer_queries[This->num_buffer_queries++] = query;
343 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
344 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
346 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
347 e->format_desc = format_desc;
348 e->stride = strided->dwStride;
349 e->data = strided->lpData;
350 e->stream_idx = 0;
351 e->buffer_object = 0;
354 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
355 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
357 unsigned int i;
359 memset(stream_info, 0, sizeof(*stream_info));
361 if (strided->position.lpData)
362 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
363 if (strided->normal.lpData)
364 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
365 if (strided->diffuse.lpData)
366 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
367 if (strided->specular.lpData)
368 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
370 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
372 if (strided->texCoords[i].lpData)
373 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
374 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
377 stream_info->position_transformed = strided->position_transformed;
379 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
381 if (!stream_info->elements[i].format_desc) continue;
383 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
384 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
386 stream_info->swizzle_map |= 1 << i;
388 stream_info->use_map |= 1 << i;
392 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
394 TRACE("Strided Data:\n");
395 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
412 /* Context activation is done by the caller. */
413 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
415 struct wined3d_stream_info *stream_info = &device->strided_streams;
416 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
417 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
418 BOOL fixup = FALSE;
420 if (device->up_strided)
422 /* Note: this is a ddraw fixed-function code path. */
423 TRACE("=============================== Strided Input ================================\n");
424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
427 else
429 TRACE("============================= Vertex Declaration =============================\n");
430 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
433 if (vs && !stream_info->position_transformed)
435 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
438 device->useDrawStridedSlow = TRUE;
440 else
442 device->useDrawStridedSlow = FALSE;
445 else
447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
453 device->useDrawStridedSlow = TRUE;
455 else
457 device->useDrawStridedSlow = FALSE;
462 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
464 IWineD3DBaseTextureImpl *texture;
465 enum WINED3DSRGB srgb;
467 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
468 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
469 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
472 void device_preload_textures(IWineD3DDeviceImpl *device)
474 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
475 unsigned int i;
477 if (use_vs(stateblock))
479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
486 if (use_ps(stateblock))
488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
490 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
491 device_preload_texture(stateblock, i);
494 else
496 WORD ffu_map = device->fixed_function_usage_map;
498 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
500 if (ffu_map & 1)
501 device_preload_texture(stateblock, i);
506 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
508 struct wined3d_context **new_array;
510 TRACE("Adding context %p.\n", context);
512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
515 if (!new_array)
517 ERR("Failed to grow the context array.\n");
518 return FALSE;
521 new_array[device->numContexts++] = context;
522 device->contexts = new_array;
523 return TRUE;
526 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
528 struct wined3d_context **new_array;
529 BOOL found = FALSE;
530 UINT i;
532 TRACE("Removing context %p.\n", context);
534 for (i = 0; i < device->numContexts; ++i)
536 if (device->contexts[i] == context)
538 found = TRUE;
539 break;
543 if (!found)
545 ERR("Context %p doesn't exist in context array.\n", context);
546 return;
549 if (!--device->numContexts)
551 HeapFree(GetProcessHeap(), 0, device->contexts);
552 device->contexts = NULL;
553 return;
556 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
557 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
558 if (!new_array)
560 ERR("Failed to shrink context array. Oh well.\n");
561 return;
564 device->contexts = new_array;
567 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
569 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
570 WINED3DVIEWPORT *vp = &stateblock->viewport;
572 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
574 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
576 IntersectRect(rect, rect, &stateblock->scissorRect);
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 /**********************************************************
596 * IUnknown parts follows
597 **********************************************************/
599 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
603 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
604 if (IsEqualGUID(riid, &IID_IUnknown)
605 || IsEqualGUID(riid, &IID_IWineD3DBase)
606 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
607 IUnknown_AddRef(iface);
608 *ppobj = This;
609 return S_OK;
611 *ppobj = NULL;
612 return E_NOINTERFACE;
615 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
617 ULONG refCount = InterlockedIncrement(&This->ref);
619 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
620 return refCount;
623 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 ULONG refCount = InterlockedDecrement(&This->ref);
627 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
629 if (!refCount) {
630 UINT i;
632 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
633 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
634 This->multistate_funcs[i] = NULL;
637 /* TODO: Clean up all the surfaces and textures! */
638 /* NOTE: You must release the parent if the object was created via a callback
639 ** ***************************/
641 if (!list_empty(&This->resources))
643 IWineD3DResourceImpl *resource;
644 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
646 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
648 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
649 FIXME("Leftover resource %p with type %s (%#x).\n",
650 resource, debug_d3dresourcetype(type), type);
654 if(This->contexts) ERR("Context array not freed!\n");
655 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
656 This->haveHardwareCursor = FALSE;
658 IWineD3D_Release(This->wined3d);
659 This->wined3d = NULL;
660 HeapFree(GetProcessHeap(), 0, This);
661 TRACE("Freed device %p\n", This);
662 This = NULL;
664 return refCount;
667 /**********************************************************
668 * IWineD3DDevice implementation follows
669 **********************************************************/
670 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
672 *pParent = This->parent;
673 IUnknown_AddRef(This->parent);
674 return WINED3D_OK;
677 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
678 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
681 struct wined3d_buffer *object;
682 HRESULT hr;
684 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
686 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
687 if (!object)
689 ERR("Failed to allocate memory\n");
690 return E_OUTOFMEMORY;
693 FIXME("Ignoring access flags (pool)\n");
695 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
696 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
697 if (FAILED(hr))
699 WARN("Failed to initialize buffer, hr %#x.\n", hr);
700 HeapFree(GetProcessHeap(), 0, object);
701 return hr;
703 object->desc = *desc;
705 TRACE("Created buffer %p.\n", object);
707 *buffer = (IWineD3DBuffer *)object;
709 return WINED3D_OK;
712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
713 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
714 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
717 struct wined3d_buffer *object;
718 HRESULT hr;
720 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
721 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
723 if (Pool == WINED3DPOOL_SCRATCH)
725 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
726 * anyway, SCRATCH vertex buffers aren't usable anywhere
728 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
729 *ppVertexBuffer = NULL;
730 return WINED3DERR_INVALIDCALL;
733 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
734 if (!object)
736 ERR("Out of memory\n");
737 *ppVertexBuffer = NULL;
738 return WINED3DERR_OUTOFVIDEOMEMORY;
741 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
742 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
743 if (FAILED(hr))
745 WARN("Failed to initialize buffer, hr %#x.\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
747 return hr;
750 TRACE("Created buffer %p.\n", object);
751 *ppVertexBuffer = (IWineD3DBuffer *)object;
753 return WINED3D_OK;
756 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
757 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
758 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 struct wined3d_buffer *object;
762 HRESULT hr;
764 TRACE("(%p) Creating index buffer\n", This);
766 /* Allocate the storage for the device */
767 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
768 if (!object)
770 ERR("Out of memory\n");
771 *ppIndexBuffer = NULL;
772 return WINED3DERR_OUTOFVIDEOMEMORY;
775 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
776 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
777 parent, parent_ops);
778 if (FAILED(hr))
780 WARN("Failed to initialize buffer, hr %#x\n", hr);
781 HeapFree(GetProcessHeap(), 0, object);
782 return hr;
785 TRACE("Created buffer %p.\n", object);
787 *ppIndexBuffer = (IWineD3DBuffer *) object;
789 return WINED3D_OK;
792 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
793 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
796 IWineD3DStateBlockImpl *object;
797 HRESULT hr;
799 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
800 if(!object)
802 ERR("Failed to allocate stateblock memory.\n");
803 return E_OUTOFMEMORY;
806 hr = stateblock_init(object, This, type);
807 if (FAILED(hr))
809 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
810 HeapFree(GetProcessHeap(), 0, object);
811 return hr;
814 TRACE("Created stateblock %p.\n", object);
815 *stateblock = (IWineD3DStateBlock *)object;
817 return WINED3D_OK;
820 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
821 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
822 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
823 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
826 IWineD3DSurfaceImpl *object;
827 HRESULT hr;
829 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
830 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
831 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
832 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
833 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
835 if (Impl == SURFACE_OPENGL && !This->adapter)
837 ERR("OpenGL surfaces are not available without OpenGL.\n");
838 return WINED3DERR_NOTAVAILABLE;
841 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
842 if (!object)
844 ERR("Failed to allocate surface memory.\n");
845 return WINED3DERR_OUTOFVIDEOMEMORY;
848 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
849 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
850 if (FAILED(hr))
852 WARN("Failed to initialize surface, returning %#x.\n", hr);
853 HeapFree(GetProcessHeap(), 0, object);
854 return hr;
857 TRACE("(%p) : Created surface %p\n", This, object);
859 *ppSurface = (IWineD3DSurface *)object;
861 return hr;
864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
865 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
867 struct wined3d_rendertarget_view *object;
869 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
870 iface, resource, parent, rendertarget_view);
872 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
873 if (!object)
875 ERR("Failed to allocate memory\n");
876 return E_OUTOFMEMORY;
879 wined3d_rendertarget_view_init(object, resource, parent);
881 TRACE("Created render target view %p.\n", object);
882 *rendertarget_view = (IWineD3DRendertargetView *)object;
884 return WINED3D_OK;
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
889 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
892 IWineD3DTextureImpl *object;
893 HRESULT hr;
895 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
896 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
897 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
899 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
900 if (!object)
902 ERR("Out of memory\n");
903 *ppTexture = NULL;
904 return WINED3DERR_OUTOFVIDEOMEMORY;
907 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
908 if (FAILED(hr))
910 WARN("Failed to initialize texture, returning %#x\n", hr);
911 HeapFree(GetProcessHeap(), 0, object);
912 *ppTexture = NULL;
913 return hr;
916 *ppTexture = (IWineD3DTexture *)object;
918 TRACE("(%p) : Created texture %p\n", This, object);
920 return WINED3D_OK;
923 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
924 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
925 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
928 IWineD3DVolumeTextureImpl *object;
929 HRESULT hr;
931 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
932 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
934 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
935 if (!object)
937 ERR("Out of memory\n");
938 *ppVolumeTexture = NULL;
939 return WINED3DERR_OUTOFVIDEOMEMORY;
942 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
943 if (FAILED(hr))
945 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
946 HeapFree(GetProcessHeap(), 0, object);
947 *ppVolumeTexture = NULL;
948 return hr;
951 TRACE("(%p) : Created volume texture %p.\n", This, object);
952 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
954 return WINED3D_OK;
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
958 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
959 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
962 IWineD3DVolumeImpl *object;
963 HRESULT hr;
965 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
966 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
968 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
969 if (!object)
971 ERR("Out of memory\n");
972 *ppVolume = NULL;
973 return WINED3DERR_OUTOFVIDEOMEMORY;
976 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
977 if (FAILED(hr))
979 WARN("Failed to initialize volume, returning %#x.\n", hr);
980 HeapFree(GetProcessHeap(), 0, object);
981 return hr;
984 TRACE("(%p) : Created volume %p.\n", This, object);
985 *ppVolume = (IWineD3DVolume *)object;
987 return WINED3D_OK;
990 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
991 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
992 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
996 HRESULT hr;
998 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
999 if (!object)
1001 ERR("Out of memory\n");
1002 *ppCubeTexture = NULL;
1003 return WINED3DERR_OUTOFVIDEOMEMORY;
1006 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1007 if (FAILED(hr))
1009 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1010 HeapFree(GetProcessHeap(), 0, object);
1011 *ppCubeTexture = NULL;
1012 return hr;
1015 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1016 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1018 return WINED3D_OK;
1021 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1022 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1025 IWineD3DQueryImpl *object;
1026 HRESULT hr;
1028 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1030 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1031 if (!object)
1033 ERR("Failed to allocate query memory.\n");
1034 return E_OUTOFMEMORY;
1037 hr = query_init(object, This, type, parent);
1038 if (FAILED(hr))
1040 WARN("Failed to initialize query, hr %#x.\n", hr);
1041 HeapFree(GetProcessHeap(), 0, object);
1042 return hr;
1045 TRACE("Created query %p.\n", object);
1046 *query = (IWineD3DQuery *)object;
1048 return WINED3D_OK;
1051 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1052 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1053 IUnknown *parent, WINED3DSURFTYPE surface_type)
1055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1056 IWineD3DSwapChainImpl *object;
1057 HRESULT hr;
1059 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1060 iface, present_parameters, swapchain, parent, surface_type);
1062 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1063 if (!object)
1065 ERR("Failed to allocate swapchain memory.\n");
1066 return E_OUTOFMEMORY;
1069 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1070 if (FAILED(hr))
1072 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1073 HeapFree(GetProcessHeap(), 0, object);
1074 return hr;
1077 TRACE("Created swapchain %p.\n", object);
1078 *swapchain = (IWineD3DSwapChain *)object;
1080 return WINED3D_OK;
1083 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1084 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1086 TRACE("(%p)\n", This);
1088 return This->NumberOfSwapChains;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1093 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1095 if(iSwapChain < This->NumberOfSwapChains) {
1096 *pSwapChain = This->swapchains[iSwapChain];
1097 IWineD3DSwapChain_AddRef(*pSwapChain);
1098 TRACE("(%p) returning %p\n", This, *pSwapChain);
1099 return WINED3D_OK;
1100 } else {
1101 TRACE("Swapchain out of range\n");
1102 *pSwapChain = NULL;
1103 return WINED3DERR_INVALIDCALL;
1107 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1108 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1109 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1112 IWineD3DVertexDeclarationImpl *object = NULL;
1113 HRESULT hr;
1115 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1116 iface, declaration, parent, elements, element_count);
1118 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1119 if(!object)
1121 ERR("Failed to allocate vertex declaration memory.\n");
1122 return E_OUTOFMEMORY;
1125 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1126 if (FAILED(hr))
1128 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1129 HeapFree(GetProcessHeap(), 0, object);
1130 return hr;
1133 TRACE("Created vertex declaration %p.\n", object);
1134 *declaration = (IWineD3DVertexDeclaration *)object;
1136 return WINED3D_OK;
1139 struct wined3d_fvf_convert_state
1141 const struct wined3d_gl_info *gl_info;
1142 WINED3DVERTEXELEMENT *elements;
1143 UINT offset;
1144 UINT idx;
1147 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1148 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1150 WINED3DVERTEXELEMENT *elements = state->elements;
1151 const struct wined3d_format_desc *format_desc;
1152 UINT offset = state->offset;
1153 UINT idx = state->idx;
1155 elements[idx].format = format;
1156 elements[idx].input_slot = 0;
1157 elements[idx].offset = offset;
1158 elements[idx].output_slot = 0;
1159 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1160 elements[idx].usage = usage;
1161 elements[idx].usage_idx = usage_idx;
1163 format_desc = getFormatDescEntry(format, state->gl_info);
1164 state->offset += format_desc->component_count * format_desc->component_size;
1165 ++state->idx;
1168 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1169 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1171 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1172 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1173 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1174 BOOL has_blend_idx = has_blend &&
1175 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1176 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1177 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1178 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1179 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1180 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1181 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1183 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1184 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1185 struct wined3d_fvf_convert_state state;
1186 unsigned int size;
1187 unsigned int idx;
1188 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1189 if (has_blend_idx) num_blends--;
1191 /* Compute declaration size */
1192 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1193 has_psize + has_diffuse + has_specular + num_textures;
1195 state.gl_info = gl_info;
1196 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1197 if (!state.elements) return ~0U;
1198 state.offset = 0;
1199 state.idx = 0;
1201 if (has_pos)
1203 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1204 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1205 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1206 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1207 else
1208 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1211 if (has_blend && (num_blends > 0))
1213 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1214 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1215 else
1217 switch (num_blends)
1219 case 1:
1220 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1221 break;
1222 case 2:
1223 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1224 break;
1225 case 3:
1226 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1227 break;
1228 case 4:
1229 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1230 break;
1231 default:
1232 ERR("Unexpected amount of blend values: %u\n", num_blends);
1237 if (has_blend_idx)
1239 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1240 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1241 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1242 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1243 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1244 else
1245 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1248 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1249 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1250 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1251 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1253 for (idx = 0; idx < num_textures; ++idx)
1255 switch ((texcoords >> (idx * 2)) & 0x03)
1257 case WINED3DFVF_TEXTUREFORMAT1:
1258 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1259 break;
1260 case WINED3DFVF_TEXTUREFORMAT2:
1261 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1262 break;
1263 case WINED3DFVF_TEXTUREFORMAT3:
1264 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1265 break;
1266 case WINED3DFVF_TEXTUREFORMAT4:
1267 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1268 break;
1272 *ppVertexElements = state.elements;
1273 return size;
1276 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1277 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1278 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1281 WINED3DVERTEXELEMENT *elements;
1282 unsigned int size;
1283 DWORD hr;
1285 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1287 size = ConvertFvfToDeclaration(This, fvf, &elements);
1288 if (size == ~0U) return E_OUTOFMEMORY;
1290 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1291 HeapFree(GetProcessHeap(), 0, elements);
1292 return hr;
1295 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1296 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1297 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1298 const struct wined3d_parent_ops *parent_ops)
1300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1301 IWineD3DVertexShaderImpl *object;
1302 HRESULT hr;
1304 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1305 if (!object)
1307 ERR("Failed to allocate shader memory.\n");
1308 return E_OUTOFMEMORY;
1311 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1312 if (FAILED(hr))
1314 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1315 HeapFree(GetProcessHeap(), 0, object);
1316 return hr;
1319 TRACE("Created vertex shader %p.\n", object);
1320 *ppVertexShader = (IWineD3DVertexShader *)object;
1322 return WINED3D_OK;
1325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1326 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1327 IWineD3DGeometryShader **shader, IUnknown *parent,
1328 const struct wined3d_parent_ops *parent_ops)
1330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1331 struct wined3d_geometryshader *object;
1332 HRESULT hr;
1334 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1335 if (!object)
1337 ERR("Failed to allocate shader memory.\n");
1338 return E_OUTOFMEMORY;
1341 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1342 if (FAILED(hr))
1344 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1345 HeapFree(GetProcessHeap(), 0, object);
1346 return hr;
1349 TRACE("Created geometry shader %p.\n", object);
1350 *shader = (IWineD3DGeometryShader *)object;
1352 return WINED3D_OK;
1355 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1356 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1357 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1358 const struct wined3d_parent_ops *parent_ops)
1360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1361 IWineD3DPixelShaderImpl *object;
1362 HRESULT hr;
1364 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1365 if (!object)
1367 ERR("Failed to allocate shader memory.\n");
1368 return E_OUTOFMEMORY;
1371 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1372 if (FAILED(hr))
1374 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1375 HeapFree(GetProcessHeap(), 0, object);
1376 return hr;
1379 TRACE("Created pixel shader %p.\n", object);
1380 *ppPixelShader = (IWineD3DPixelShader *)object;
1382 return WINED3D_OK;
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1386 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1389 IWineD3DPaletteImpl *object;
1390 HRESULT hr;
1392 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1393 iface, Flags, PalEnt, Palette, Parent);
1395 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1396 if (!object)
1398 ERR("Failed to allocate palette memory.\n");
1399 return E_OUTOFMEMORY;
1402 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1403 if (FAILED(hr))
1405 WARN("Failed to initialize palette, hr %#x.\n", hr);
1406 HeapFree(GetProcessHeap(), 0, object);
1407 return hr;
1410 TRACE("Created palette %p.\n", object);
1411 *Palette = (IWineD3DPalette *)object;
1413 return WINED3D_OK;
1416 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1417 HBITMAP hbm;
1418 BITMAP bm;
1419 HRESULT hr;
1420 HDC dcb = NULL, dcs = NULL;
1421 WINEDDCOLORKEY colorkey;
1423 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1424 if(hbm)
1426 GetObjectA(hbm, sizeof(BITMAP), &bm);
1427 dcb = CreateCompatibleDC(NULL);
1428 if(!dcb) goto out;
1429 SelectObject(dcb, hbm);
1431 else
1433 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1434 * couldn't be loaded
1436 memset(&bm, 0, sizeof(bm));
1437 bm.bmWidth = 32;
1438 bm.bmHeight = 32;
1441 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1442 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1443 NULL, &wined3d_null_parent_ops);
1444 if(FAILED(hr)) {
1445 ERR("Wine logo requested, but failed to create surface\n");
1446 goto out;
1449 if(dcb) {
1450 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1451 if(FAILED(hr)) goto out;
1452 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1453 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1455 colorkey.dwColorSpaceLowValue = 0;
1456 colorkey.dwColorSpaceHighValue = 0;
1457 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1458 } else {
1459 /* Fill the surface with a white color to show that wined3d is there */
1460 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1463 out:
1464 if (dcb) DeleteDC(dcb);
1465 if (hbm) DeleteObject(hbm);
1468 /* Context activation is done by the caller. */
1469 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1471 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1472 unsigned int i;
1473 /* Under DirectX you can have texture stage operations even if no texture is
1474 bound, whereas opengl will only do texture operations when a valid texture is
1475 bound. We emulate this by creating dummy textures and binding them to each
1476 texture stage, but disable all stages by default. Hence if a stage is enabled
1477 then the default texture will kick in until replaced by a SetTexture call */
1478 ENTER_GL();
1480 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1482 /* The dummy texture does not have client storage backing */
1483 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1484 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1487 for (i = 0; i < gl_info->limits.textures; ++i)
1489 GLubyte white = 255;
1491 /* Make appropriate texture active */
1492 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1493 checkGLcall("glActiveTextureARB");
1495 /* Generate an opengl texture name */
1496 glGenTextures(1, &This->dummyTextureName[i]);
1497 checkGLcall("glGenTextures");
1498 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1500 /* Generate a dummy 2d texture (not using 1d because they cause many
1501 * DRI drivers fall back to sw) */
1502 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1503 checkGLcall("glBindTexture");
1505 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1506 checkGLcall("glTexImage2D");
1509 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1511 /* Reenable because if supported it is enabled by default */
1512 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1513 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1516 LEAVE_GL();
1519 /* Context activation is done by the caller. */
1520 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1522 ENTER_GL();
1523 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1524 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1525 LEAVE_GL();
1527 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1530 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1532 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1534 if (!wined3d_register_window(window, device))
1536 ERR("Failed to register window %p.\n", window);
1537 return E_FAIL;
1540 device->focus_window = window;
1541 SetForegroundWindow(window);
1543 return WINED3D_OK;
1546 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1548 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1550 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1551 device->focus_window = NULL;
1554 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1555 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1558 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1559 IWineD3DSwapChainImpl *swapchain = NULL;
1560 struct wined3d_context *context;
1561 HRESULT hr;
1562 DWORD state;
1563 unsigned int i;
1565 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1567 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1568 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1570 TRACE("(%p) : Creating stateblock\n", This);
1571 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1572 hr = IWineD3DDevice_CreateStateBlock(iface,
1573 WINED3DSBT_INIT,
1574 (IWineD3DStateBlock **)&This->stateBlock,
1575 NULL);
1576 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1577 WARN("Failed to create stateblock\n");
1578 goto err_out;
1580 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1581 This->updateStateBlock = This->stateBlock;
1582 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1584 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1585 sizeof(*This->render_targets) * gl_info->limits.buffers);
1586 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1587 sizeof(GLenum) * gl_info->limits.buffers);
1589 This->NumberOfPalettes = 1;
1590 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1591 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1592 ERR("Out of memory!\n");
1593 hr = E_OUTOFMEMORY;
1594 goto err_out;
1596 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1597 if(!This->palettes[0]) {
1598 ERR("Out of memory!\n");
1599 hr = E_OUTOFMEMORY;
1600 goto err_out;
1602 for (i = 0; i < 256; ++i) {
1603 This->palettes[0][i].peRed = 0xFF;
1604 This->palettes[0][i].peGreen = 0xFF;
1605 This->palettes[0][i].peBlue = 0xFF;
1606 This->palettes[0][i].peFlags = 0xFF;
1608 This->currentPalette = 0;
1610 /* Initialize the texture unit mapping to a 1:1 mapping */
1611 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1613 if (state < gl_info->limits.fragment_samplers)
1615 This->texUnitMap[state] = state;
1616 This->rev_tex_unit_map[state] = state;
1617 } else {
1618 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1619 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1623 /* Setup the implicit swapchain. This also initializes a context. */
1624 TRACE("Creating implicit swapchain\n");
1625 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1626 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1627 if (FAILED(hr))
1629 WARN("Failed to create implicit swapchain\n");
1630 goto err_out;
1633 This->NumberOfSwapChains = 1;
1634 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1635 if(!This->swapchains) {
1636 ERR("Out of memory!\n");
1637 goto err_out;
1639 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1641 if (swapchain->back_buffers && swapchain->back_buffers[0])
1643 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1644 This->render_targets[0] = swapchain->back_buffers[0];
1646 else
1648 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1649 This->render_targets[0] = swapchain->front_buffer;
1651 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1653 /* Depth Stencil support */
1654 This->depth_stencil = This->auto_depth_stencil;
1655 if (This->depth_stencil)
1656 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1658 hr = This->shader_backend->shader_alloc_private(iface);
1659 if(FAILED(hr)) {
1660 TRACE("Shader private data couldn't be allocated\n");
1661 goto err_out;
1663 hr = This->frag_pipe->alloc_private(iface);
1664 if(FAILED(hr)) {
1665 TRACE("Fragment pipeline private data couldn't be allocated\n");
1666 goto err_out;
1668 hr = This->blitter->alloc_private(iface);
1669 if(FAILED(hr)) {
1670 TRACE("Blitter private data couldn't be allocated\n");
1671 goto err_out;
1674 /* Set up some starting GL setup */
1676 /* Setup all the devices defaults */
1677 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1679 context = context_acquire(This, swapchain->front_buffer);
1681 create_dummy_textures(This);
1683 ENTER_GL();
1685 /* Initialize the current view state */
1686 This->view_ident = 1;
1687 This->contexts[0]->last_was_rhw = 0;
1688 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1689 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1691 switch(wined3d_settings.offscreen_rendering_mode) {
1692 case ORM_FBO:
1693 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1694 break;
1696 case ORM_BACKBUFFER:
1698 if (context_get_current()->aux_buffers > 0)
1700 TRACE("Using auxilliary buffer for offscreen rendering\n");
1701 This->offscreenBuffer = GL_AUX0;
1702 } else {
1703 TRACE("Using back buffer for offscreen rendering\n");
1704 This->offscreenBuffer = GL_BACK;
1709 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1710 LEAVE_GL();
1712 context_release(context);
1714 /* Clear the screen */
1715 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1716 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1717 0x00, 1.0f, 0);
1719 This->d3d_initialized = TRUE;
1721 if(wined3d_settings.logo) {
1722 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1724 This->highest_dirty_ps_const = 0;
1725 This->highest_dirty_vs_const = 0;
1726 return WINED3D_OK;
1728 err_out:
1729 HeapFree(GetProcessHeap(), 0, This->render_targets);
1730 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1731 HeapFree(GetProcessHeap(), 0, This->swapchains);
1732 This->NumberOfSwapChains = 0;
1733 if(This->palettes) {
1734 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1735 HeapFree(GetProcessHeap(), 0, This->palettes);
1737 This->NumberOfPalettes = 0;
1738 if(swapchain) {
1739 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1741 if(This->stateBlock) {
1742 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1743 This->stateBlock = NULL;
1745 if (This->blit_priv) {
1746 This->blitter->free_private(iface);
1748 if (This->fragment_priv) {
1749 This->frag_pipe->free_private(iface);
1751 if (This->shader_priv) {
1752 This->shader_backend->shader_free_private(iface);
1754 return hr;
1757 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1758 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1761 IWineD3DSwapChainImpl *swapchain = NULL;
1762 HRESULT hr;
1764 /* Setup the implicit swapchain */
1765 TRACE("Creating implicit swapchain\n");
1766 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1767 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1768 if (FAILED(hr))
1770 WARN("Failed to create implicit swapchain\n");
1771 goto err_out;
1774 This->NumberOfSwapChains = 1;
1775 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1776 if(!This->swapchains) {
1777 ERR("Out of memory!\n");
1778 goto err_out;
1780 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1781 return WINED3D_OK;
1783 err_out:
1784 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1785 return hr;
1788 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1790 IWineD3DResource_UnLoad(resource);
1791 IWineD3DResource_Release(resource);
1792 return WINED3D_OK;
1795 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1796 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1799 const struct wined3d_gl_info *gl_info;
1800 struct wined3d_context *context;
1801 int sampler;
1802 UINT i;
1803 TRACE("(%p)\n", This);
1805 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1807 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1808 * it was created. Thus make sure a context is active for the glDelete* calls
1810 context = context_acquire(This, NULL);
1811 gl_info = context->gl_info;
1813 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1815 /* Unload resources */
1816 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1818 TRACE("Deleting high order patches\n");
1819 for(i = 0; i < PATCHMAP_SIZE; i++) {
1820 struct list *e1, *e2;
1821 struct WineD3DRectPatch *patch;
1822 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1823 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1824 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1828 /* Delete the mouse cursor texture */
1829 if(This->cursorTexture) {
1830 ENTER_GL();
1831 glDeleteTextures(1, &This->cursorTexture);
1832 LEAVE_GL();
1833 This->cursorTexture = 0;
1836 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1837 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1839 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1840 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1843 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1844 * private data, it might contain opengl pointers
1846 if(This->depth_blt_texture) {
1847 ENTER_GL();
1848 glDeleteTextures(1, &This->depth_blt_texture);
1849 LEAVE_GL();
1850 This->depth_blt_texture = 0;
1852 if (This->depth_blt_rb) {
1853 ENTER_GL();
1854 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1855 LEAVE_GL();
1856 This->depth_blt_rb = 0;
1857 This->depth_blt_rb_w = 0;
1858 This->depth_blt_rb_h = 0;
1861 /* Release the update stateblock */
1862 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1863 if(This->updateStateBlock != This->stateBlock)
1864 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1866 This->updateStateBlock = NULL;
1868 { /* because were not doing proper internal refcounts releasing the primary state block
1869 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1870 to set this->stateBlock = NULL; first */
1871 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1872 This->stateBlock = NULL;
1874 /* Release the stateblock */
1875 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1876 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1880 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1881 This->blitter->free_private(iface);
1882 This->frag_pipe->free_private(iface);
1883 This->shader_backend->shader_free_private(iface);
1885 /* Release the buffers (with sanity checks)*/
1886 if (This->onscreen_depth_stencil)
1888 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1889 This->onscreen_depth_stencil = NULL;
1892 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1893 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1895 if (This->auto_depth_stencil != This->depth_stencil)
1896 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1898 This->depth_stencil = NULL;
1900 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1901 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1903 TRACE("Setting rendertarget to NULL\n");
1904 This->render_targets[0] = NULL;
1906 if (This->auto_depth_stencil)
1908 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1910 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1912 This->auto_depth_stencil = NULL;
1915 context_release(context);
1917 for(i=0; i < This->NumberOfSwapChains; i++) {
1918 TRACE("Releasing the implicit swapchain %d\n", i);
1919 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1920 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1924 HeapFree(GetProcessHeap(), 0, This->swapchains);
1925 This->swapchains = NULL;
1926 This->NumberOfSwapChains = 0;
1928 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1929 HeapFree(GetProcessHeap(), 0, This->palettes);
1930 This->palettes = NULL;
1931 This->NumberOfPalettes = 0;
1933 HeapFree(GetProcessHeap(), 0, This->render_targets);
1934 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1935 This->render_targets = NULL;
1936 This->draw_buffers = NULL;
1938 This->d3d_initialized = FALSE;
1940 return WINED3D_OK;
1943 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1945 unsigned int i;
1947 for(i=0; i < This->NumberOfSwapChains; i++) {
1948 TRACE("Releasing the implicit swapchain %d\n", i);
1949 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1950 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1954 HeapFree(GetProcessHeap(), 0, This->swapchains);
1955 This->swapchains = NULL;
1956 This->NumberOfSwapChains = 0;
1957 return WINED3D_OK;
1960 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1961 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1962 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1964 * There is no way to deactivate thread safety once it is enabled.
1966 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1969 /*For now just store the flag(needed in case of ddraw) */
1970 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1973 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1974 const WINED3DDISPLAYMODE* pMode) {
1975 DEVMODEW devmode;
1976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1977 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1978 LONG ret;
1979 RECT clip_rc;
1981 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1983 /* Resize the screen even without a window:
1984 * The app could have unset it with SetCooperativeLevel, but not called
1985 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1986 * but we don't have any hwnd
1989 memset(&devmode, 0, sizeof(devmode));
1990 devmode.dmSize = sizeof(devmode);
1991 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1992 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1993 devmode.dmPelsWidth = pMode->Width;
1994 devmode.dmPelsHeight = pMode->Height;
1996 devmode.dmDisplayFrequency = pMode->RefreshRate;
1997 if (pMode->RefreshRate != 0) {
1998 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2001 /* Only change the mode if necessary */
2002 if( (This->ddraw_width == pMode->Width) &&
2003 (This->ddraw_height == pMode->Height) &&
2004 (This->ddraw_format == pMode->Format) &&
2005 (pMode->RefreshRate == 0) ) {
2006 return WINED3D_OK;
2009 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2010 if (ret != DISP_CHANGE_SUCCESSFUL) {
2011 if(devmode.dmDisplayFrequency != 0) {
2012 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2013 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2014 devmode.dmDisplayFrequency = 0;
2015 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2017 if(ret != DISP_CHANGE_SUCCESSFUL) {
2018 return WINED3DERR_NOTAVAILABLE;
2022 /* Store the new values */
2023 This->ddraw_width = pMode->Width;
2024 This->ddraw_height = pMode->Height;
2025 This->ddraw_format = pMode->Format;
2027 /* And finally clip mouse to our screen */
2028 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2029 ClipCursor(&clip_rc);
2031 return WINED3D_OK;
2034 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2036 *ppD3D = This->wined3d;
2037 TRACE("Returning %p.\n", *ppD3D);
2038 IWineD3D_AddRef(*ppD3D);
2039 return WINED3D_OK;
2042 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2045 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2046 (This->adapter->TextureRam/(1024*1024)),
2047 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2048 /* return simulated texture memory left */
2049 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2052 /*****
2053 * Get / Set Stream Source
2054 *****/
2055 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2056 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2059 IWineD3DBuffer *oldSrc;
2061 if (StreamNumber >= MAX_STREAMS) {
2062 WARN("Stream out of range %d\n", StreamNumber);
2063 return WINED3DERR_INVALIDCALL;
2064 } else if(OffsetInBytes & 0x3) {
2065 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2066 return WINED3DERR_INVALIDCALL;
2069 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2070 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2072 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2074 if(oldSrc == pStreamData &&
2075 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2076 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2077 TRACE("Application is setting the old values over, nothing to do\n");
2078 return WINED3D_OK;
2081 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2082 if (pStreamData) {
2083 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2084 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2087 /* Handle recording of state blocks */
2088 if (This->isRecordingState) {
2089 TRACE("Recording... not performing anything\n");
2090 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2091 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2092 return WINED3D_OK;
2095 if (pStreamData != NULL) {
2096 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2097 IWineD3DBuffer_AddRef(pStreamData);
2099 if (oldSrc != NULL) {
2100 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2101 IWineD3DBuffer_Release(oldSrc);
2104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2106 return WINED3D_OK;
2109 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2110 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2115 This->stateBlock->streamSource[StreamNumber],
2116 This->stateBlock->streamOffset[StreamNumber],
2117 This->stateBlock->streamStride[StreamNumber]);
2119 if (StreamNumber >= MAX_STREAMS) {
2120 WARN("Stream out of range %d\n", StreamNumber);
2121 return WINED3DERR_INVALIDCALL;
2123 *pStream = This->stateBlock->streamSource[StreamNumber];
2124 *pStride = This->stateBlock->streamStride[StreamNumber];
2125 if (pOffset) {
2126 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2129 if (*pStream != NULL) {
2130 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2132 return WINED3D_OK;
2135 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2137 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2138 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2140 /* Verify input at least in d3d9 this is invalid*/
2141 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2142 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2143 return WINED3DERR_INVALIDCALL;
2145 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2146 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2147 return WINED3DERR_INVALIDCALL;
2149 if( Divider == 0 ){
2150 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2151 return WINED3DERR_INVALIDCALL;
2154 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2155 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2157 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2158 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2160 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2161 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2165 return WINED3D_OK;
2168 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2171 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2172 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2174 TRACE("(%p) : returning %d\n", This, *Divider);
2176 return WINED3D_OK;
2179 /*****
2180 * Get / Set & Multiply Transform
2181 *****/
2182 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2185 /* Most of this routine, comments included copied from ddraw tree initially: */
2186 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2188 /* Handle recording of state blocks */
2189 if (This->isRecordingState) {
2190 TRACE("Recording... not performing anything\n");
2191 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2192 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2193 return WINED3D_OK;
2197 * If the new matrix is the same as the current one,
2198 * we cut off any further processing. this seems to be a reasonable
2199 * optimization because as was noticed, some apps (warcraft3 for example)
2200 * tend towards setting the same matrix repeatedly for some reason.
2202 * From here on we assume that the new matrix is different, wherever it matters.
2204 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2205 TRACE("The app is setting the same matrix over again\n");
2206 return WINED3D_OK;
2207 } else {
2208 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2212 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2213 where ViewMat = Camera space, WorldMat = world space.
2215 In OpenGL, camera and world space is combined into GL_MODELVIEW
2216 matrix. The Projection matrix stay projection matrix.
2219 /* Capture the times we can just ignore the change for now */
2220 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2221 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2222 /* Handled by the state manager */
2225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2226 return WINED3D_OK;
2229 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2231 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2232 *pMatrix = This->stateBlock->transforms[State];
2233 return WINED3D_OK;
2236 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2237 const WINED3DMATRIX *mat = NULL;
2238 WINED3DMATRIX temp;
2240 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2241 * below means it will be recorded in a state block change, but it
2242 * works regardless where it is recorded.
2243 * If this is found to be wrong, change to StateBlock.
2245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2246 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2248 if (State <= HIGHEST_TRANSFORMSTATE)
2250 mat = &This->updateStateBlock->transforms[State];
2251 } else {
2252 FIXME("Unhandled transform state!!\n");
2255 multiply_matrix(&temp, mat, pMatrix);
2257 /* Apply change via set transform - will reapply to eg. lights this way */
2258 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2261 /*****
2262 * Get / Set Light
2263 *****/
2264 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2265 you can reference any indexes you want as long as that number max are enabled at any
2266 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2267 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2268 but when recording, just build a chain pretty much of commands to be replayed. */
2270 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2271 float rho;
2272 struct wined3d_light_info *object = NULL;
2273 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2274 struct list *e;
2276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2277 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2279 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2280 * the gl driver.
2282 if(!pLight) {
2283 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2284 return WINED3DERR_INVALIDCALL;
2287 switch(pLight->Type) {
2288 case WINED3DLIGHT_POINT:
2289 case WINED3DLIGHT_SPOT:
2290 case WINED3DLIGHT_PARALLELPOINT:
2291 case WINED3DLIGHT_GLSPOT:
2292 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2293 * most wanted
2295 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2297 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2298 return WINED3DERR_INVALIDCALL;
2300 break;
2302 case WINED3DLIGHT_DIRECTIONAL:
2303 /* Ignores attenuation */
2304 break;
2306 default:
2307 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2308 return WINED3DERR_INVALIDCALL;
2311 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2313 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2314 if(object->OriginalIndex == Index) break;
2315 object = NULL;
2318 if(!object) {
2319 TRACE("Adding new light\n");
2320 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2321 if(!object) {
2322 ERR("Out of memory error when allocating a light\n");
2323 return E_OUTOFMEMORY;
2325 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2326 object->glIndex = -1;
2327 object->OriginalIndex = Index;
2330 /* Initialize the object */
2331 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,
2332 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2333 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2334 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2335 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2336 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2337 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2339 /* Save away the information */
2340 object->OriginalParms = *pLight;
2342 switch (pLight->Type) {
2343 case WINED3DLIGHT_POINT:
2344 /* Position */
2345 object->lightPosn[0] = pLight->Position.x;
2346 object->lightPosn[1] = pLight->Position.y;
2347 object->lightPosn[2] = pLight->Position.z;
2348 object->lightPosn[3] = 1.0f;
2349 object->cutoff = 180.0f;
2350 /* FIXME: Range */
2351 break;
2353 case WINED3DLIGHT_DIRECTIONAL:
2354 /* Direction */
2355 object->lightPosn[0] = -pLight->Direction.x;
2356 object->lightPosn[1] = -pLight->Direction.y;
2357 object->lightPosn[2] = -pLight->Direction.z;
2358 object->lightPosn[3] = 0.0f;
2359 object->exponent = 0.0f;
2360 object->cutoff = 180.0f;
2361 break;
2363 case WINED3DLIGHT_SPOT:
2364 /* Position */
2365 object->lightPosn[0] = pLight->Position.x;
2366 object->lightPosn[1] = pLight->Position.y;
2367 object->lightPosn[2] = pLight->Position.z;
2368 object->lightPosn[3] = 1.0f;
2370 /* Direction */
2371 object->lightDirn[0] = pLight->Direction.x;
2372 object->lightDirn[1] = pLight->Direction.y;
2373 object->lightDirn[2] = pLight->Direction.z;
2374 object->lightDirn[3] = 1.0f;
2377 * opengl-ish and d3d-ish spot lights use too different models for the
2378 * light "intensity" as a function of the angle towards the main light direction,
2379 * so we only can approximate very roughly.
2380 * however spot lights are rather rarely used in games (if ever used at all).
2381 * furthermore if still used, probably nobody pays attention to such details.
2383 if (pLight->Falloff == 0) {
2384 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2385 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2386 * will always be 1.0 for both of them, and we don't have to care for the
2387 * rest of the rather complex calculation
2389 object->exponent = 0.0f;
2390 } else {
2391 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2392 if (rho < 0.0001f) rho = 0.0001f;
2393 object->exponent = -0.3f/logf(cosf(rho/2));
2395 if (object->exponent > 128.0f)
2397 object->exponent = 128.0f;
2399 object->cutoff = pLight->Phi*90/M_PI;
2401 /* FIXME: Range */
2402 break;
2404 default:
2405 FIXME("Unrecognized light type %d\n", pLight->Type);
2408 /* Update the live definitions if the light is currently assigned a glIndex */
2409 if (object->glIndex != -1 && !This->isRecordingState) {
2410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2412 return WINED3D_OK;
2415 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2417 struct wined3d_light_info *lightInfo = NULL;
2418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2419 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2420 struct list *e;
2421 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2423 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2425 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2426 if(lightInfo->OriginalIndex == Index) break;
2427 lightInfo = NULL;
2430 if (lightInfo == NULL) {
2431 TRACE("Light information requested but light not defined\n");
2432 return WINED3DERR_INVALIDCALL;
2435 *pLight = lightInfo->OriginalParms;
2436 return WINED3D_OK;
2439 /*****
2440 * Get / Set Light Enable
2441 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2442 *****/
2443 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2445 struct wined3d_light_info *lightInfo = NULL;
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2448 struct list *e;
2449 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2451 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2453 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2454 if(lightInfo->OriginalIndex == Index) break;
2455 lightInfo = NULL;
2457 TRACE("Found light: %p\n", lightInfo);
2459 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2460 if (lightInfo == NULL) {
2462 TRACE("Light enabled requested but light not defined, so defining one!\n");
2463 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2465 /* Search for it again! Should be fairly quick as near head of list */
2466 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2468 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2469 if(lightInfo->OriginalIndex == Index) break;
2470 lightInfo = NULL;
2472 if (lightInfo == NULL) {
2473 FIXME("Adding default lights has failed dismally\n");
2474 return WINED3DERR_INVALIDCALL;
2478 if(!Enable) {
2479 if(lightInfo->glIndex != -1) {
2480 if(!This->isRecordingState) {
2481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2484 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2485 lightInfo->glIndex = -1;
2486 } else {
2487 TRACE("Light already disabled, nothing to do\n");
2489 lightInfo->enabled = FALSE;
2490 } else {
2491 lightInfo->enabled = TRUE;
2492 if (lightInfo->glIndex != -1) {
2493 /* nop */
2494 TRACE("Nothing to do as light was enabled\n");
2495 } else {
2496 int i;
2497 /* Find a free gl light */
2498 for(i = 0; i < This->maxConcurrentLights; i++) {
2499 if(This->updateStateBlock->activeLights[i] == NULL) {
2500 This->updateStateBlock->activeLights[i] = lightInfo;
2501 lightInfo->glIndex = i;
2502 break;
2505 if(lightInfo->glIndex == -1) {
2506 /* Our tests show that Windows returns D3D_OK in this situation, even with
2507 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2508 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2509 * as well for those lights.
2511 * TODO: Test how this affects rendering
2513 WARN("Too many concurrently active lights\n");
2514 return WINED3D_OK;
2517 /* i == lightInfo->glIndex */
2518 if(!This->isRecordingState) {
2519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2524 return WINED3D_OK;
2527 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2529 struct wined3d_light_info *lightInfo = NULL;
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 struct list *e;
2532 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2533 TRACE("(%p) : for idx(%d)\n", This, Index);
2535 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2537 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2538 if(lightInfo->OriginalIndex == Index) break;
2539 lightInfo = NULL;
2542 if (lightInfo == NULL) {
2543 TRACE("Light enabled state requested but light not defined\n");
2544 return WINED3DERR_INVALIDCALL;
2546 /* true is 128 according to SetLightEnable */
2547 *pEnable = lightInfo->enabled ? 128 : 0;
2548 return WINED3D_OK;
2551 /*****
2552 * Get / Set Clip Planes
2553 *****/
2554 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2558 /* Validate Index */
2559 if (Index >= This->adapter->gl_info.limits.clipplanes)
2561 TRACE("Application has requested clipplane this device doesn't support\n");
2562 return WINED3DERR_INVALIDCALL;
2565 This->updateStateBlock->changed.clipplane |= 1 << Index;
2567 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2568 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2569 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2570 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2571 TRACE("Application is setting old values over, nothing to do\n");
2572 return WINED3D_OK;
2575 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2576 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2577 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2578 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2580 /* Handle recording of state blocks */
2581 if (This->isRecordingState) {
2582 TRACE("Recording... not performing anything\n");
2583 return WINED3D_OK;
2586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2588 return WINED3D_OK;
2591 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2593 TRACE("(%p) : for idx %d\n", This, Index);
2595 /* Validate Index */
2596 if (Index >= This->adapter->gl_info.limits.clipplanes)
2598 TRACE("Application has requested clipplane this device doesn't support\n");
2599 return WINED3DERR_INVALIDCALL;
2602 pPlane[0] = This->stateBlock->clipplane[Index][0];
2603 pPlane[1] = This->stateBlock->clipplane[Index][1];
2604 pPlane[2] = This->stateBlock->clipplane[Index][2];
2605 pPlane[3] = This->stateBlock->clipplane[Index][3];
2606 return WINED3D_OK;
2609 /*****
2610 * Get / Set Clip Plane Status
2611 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2612 *****/
2613 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 FIXME("(%p) : stub\n", This);
2616 if (NULL == pClipStatus) {
2617 return WINED3DERR_INVALIDCALL;
2619 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2620 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2621 return WINED3D_OK;
2624 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 FIXME("(%p) : stub\n", This);
2627 if (NULL == pClipStatus) {
2628 return WINED3DERR_INVALIDCALL;
2630 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2631 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2632 return WINED3D_OK;
2635 /*****
2636 * Get / Set Material
2637 *****/
2638 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 This->updateStateBlock->changed.material = TRUE;
2642 This->updateStateBlock->material = *pMaterial;
2644 /* Handle recording of state blocks */
2645 if (This->isRecordingState) {
2646 TRACE("Recording... not performing anything\n");
2647 return WINED3D_OK;
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2651 return WINED3D_OK;
2654 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 *pMaterial = This->updateStateBlock->material;
2657 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2658 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2659 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2660 pMaterial->Ambient.b, pMaterial->Ambient.a);
2661 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2662 pMaterial->Specular.b, pMaterial->Specular.a);
2663 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2664 pMaterial->Emissive.b, pMaterial->Emissive.a);
2665 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2667 return WINED3D_OK;
2670 /*****
2671 * Get / Set Indices
2672 *****/
2673 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2674 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 IWineD3DBuffer *oldIdxs;
2679 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2680 oldIdxs = This->updateStateBlock->pIndexData;
2682 This->updateStateBlock->changed.indices = TRUE;
2683 This->updateStateBlock->pIndexData = pIndexData;
2684 This->updateStateBlock->IndexFmt = fmt;
2686 /* Handle recording of state blocks */
2687 if (This->isRecordingState) {
2688 TRACE("Recording... not performing anything\n");
2689 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2690 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2691 return WINED3D_OK;
2694 if(oldIdxs != pIndexData) {
2695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2696 if(pIndexData) {
2697 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2698 IWineD3DBuffer_AddRef(pIndexData);
2700 if(oldIdxs) {
2701 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2702 IWineD3DBuffer_Release(oldIdxs);
2706 return WINED3D_OK;
2709 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 *ppIndexData = This->stateBlock->pIndexData;
2715 /* up ref count on ppindexdata */
2716 if (*ppIndexData) {
2717 IWineD3DBuffer_AddRef(*ppIndexData);
2718 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2719 }else{
2720 TRACE("(%p) No index data set\n", This);
2722 TRACE("Returning %p\n", *ppIndexData);
2724 return WINED3D_OK;
2727 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2728 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2730 TRACE("(%p)->(%d)\n", This, BaseIndex);
2732 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2733 TRACE("Application is setting the old value over, nothing to do\n");
2734 return WINED3D_OK;
2737 This->updateStateBlock->baseVertexIndex = BaseIndex;
2739 if (This->isRecordingState) {
2740 TRACE("Recording... not performing anything\n");
2741 return WINED3D_OK;
2743 /* The base vertex index affects the stream sources */
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) : base_index %p\n", This, base_index);
2752 *base_index = This->stateBlock->baseVertexIndex;
2754 TRACE("Returning %u\n", *base_index);
2756 return WINED3D_OK;
2759 /*****
2760 * Get / Set Viewports
2761 *****/
2762 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p)\n", This);
2766 This->updateStateBlock->changed.viewport = TRUE;
2767 This->updateStateBlock->viewport = *pViewport;
2769 /* Handle recording of state blocks */
2770 if (This->isRecordingState) {
2771 TRACE("Recording... not performing anything\n");
2772 return WINED3D_OK;
2775 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2776 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2779 return WINED3D_OK;
2783 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 TRACE("(%p)\n", This);
2786 *pViewport = This->stateBlock->viewport;
2787 return WINED3D_OK;
2790 /*****
2791 * Get / Set Render States
2792 * TODO: Verify against dx9 definitions
2793 *****/
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 DWORD oldValue = This->stateBlock->renderState[State];
2799 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2801 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2802 This->updateStateBlock->renderState[State] = Value;
2804 /* Handle recording of state blocks */
2805 if (This->isRecordingState) {
2806 TRACE("Recording... not performing anything\n");
2807 return WINED3D_OK;
2810 /* Compared here and not before the assignment to allow proper stateblock recording */
2811 if(Value == oldValue) {
2812 TRACE("Application is setting the old value over, nothing to do\n");
2813 } else {
2814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2817 return WINED3D_OK;
2820 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2822 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2823 *pValue = This->stateBlock->renderState[State];
2824 return WINED3D_OK;
2827 /*****
2828 * Get / Set Sampler States
2829 * TODO: Verify against dx9 definitions
2830 *****/
2832 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 DWORD oldValue;
2836 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2837 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2839 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2840 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2843 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2844 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2845 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2848 * SetSampler is designed to allow for more than the standard up to 8 textures
2849 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2850 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2852 * http://developer.nvidia.com/object/General_FAQ.html#t6
2854 * There are two new settings for GForce
2855 * the sampler one:
2856 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2857 * and the texture one:
2858 * GL_MAX_TEXTURE_COORDS_ARB.
2859 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2860 ******************/
2862 oldValue = This->stateBlock->samplerState[Sampler][Type];
2863 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2864 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2866 /* Handle recording of state blocks */
2867 if (This->isRecordingState) {
2868 TRACE("Recording... not performing anything\n");
2869 return WINED3D_OK;
2872 if(oldValue == Value) {
2873 TRACE("Application is setting the old value over, nothing to do\n");
2874 return WINED3D_OK;
2877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2879 return WINED3D_OK;
2882 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2886 This, Sampler, debug_d3dsamplerstate(Type), Type);
2888 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2889 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2892 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2893 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2894 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2896 *Value = This->stateBlock->samplerState[Sampler][Type];
2897 TRACE("(%p) : Returning %#x\n", This, *Value);
2899 return WINED3D_OK;
2902 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 This->updateStateBlock->changed.scissorRect = TRUE;
2906 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2907 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2908 return WINED3D_OK;
2910 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2912 if(This->isRecordingState) {
2913 TRACE("Recording... not performing anything\n");
2914 return WINED3D_OK;
2917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2919 return WINED3D_OK;
2922 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2925 *pRect = This->updateStateBlock->scissorRect;
2926 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2927 return WINED3D_OK;
2930 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2932 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2934 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2936 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2937 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2939 This->updateStateBlock->vertexDecl = pDecl;
2940 This->updateStateBlock->changed.vertexDecl = TRUE;
2942 if (This->isRecordingState) {
2943 TRACE("Recording... not performing anything\n");
2944 return WINED3D_OK;
2945 } else if(pDecl == oldDecl) {
2946 /* Checked after the assignment to allow proper stateblock recording */
2947 TRACE("Application is setting the old declaration over, nothing to do\n");
2948 return WINED3D_OK;
2951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2952 return WINED3D_OK;
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2960 *ppDecl = This->stateBlock->vertexDecl;
2961 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2962 return WINED3D_OK;
2965 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2969 This->updateStateBlock->vertexShader = pShader;
2970 This->updateStateBlock->changed.vertexShader = TRUE;
2972 if (This->isRecordingState) {
2973 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2974 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2975 TRACE("Recording... not performing anything\n");
2976 return WINED3D_OK;
2977 } else if(oldShader == pShader) {
2978 /* Checked here to allow proper stateblock recording */
2979 TRACE("App is setting the old shader over, nothing to do\n");
2980 return WINED3D_OK;
2983 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2984 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2985 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2989 return WINED3D_OK;
2992 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 if (NULL == ppShader) {
2996 return WINED3DERR_INVALIDCALL;
2998 *ppShader = This->stateBlock->vertexShader;
2999 if( NULL != *ppShader)
3000 IWineD3DVertexShader_AddRef(*ppShader);
3002 TRACE("(%p) : returning %p\n", This, *ppShader);
3003 return WINED3D_OK;
3006 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3007 IWineD3DDevice *iface,
3008 UINT start,
3009 CONST BOOL *srcData,
3010 UINT count) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3015 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3016 iface, srcData, start, count);
3018 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3020 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3021 for (i = 0; i < cnt; i++)
3022 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3024 for (i = start; i < cnt + start; ++i) {
3025 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3028 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3030 return WINED3D_OK;
3033 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3034 IWineD3DDevice *iface,
3035 UINT start,
3036 BOOL *dstData,
3037 UINT count) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 int cnt = min(count, MAX_CONST_B - start);
3042 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3043 iface, dstData, start, count);
3045 if (dstData == NULL || cnt < 0)
3046 return WINED3DERR_INVALIDCALL;
3048 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3049 return WINED3D_OK;
3052 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3053 IWineD3DDevice *iface,
3054 UINT start,
3055 CONST int *srcData,
3056 UINT count) {
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3061 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3062 iface, srcData, start, count);
3064 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3066 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3067 for (i = 0; i < cnt; i++)
3068 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3069 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3071 for (i = start; i < cnt + start; ++i) {
3072 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3075 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3081 IWineD3DDevice *iface,
3082 UINT start,
3083 int *dstData,
3084 UINT count) {
3086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3087 int cnt = min(count, MAX_CONST_I - start);
3089 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3090 iface, dstData, start, count);
3092 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3093 return WINED3DERR_INVALIDCALL;
3095 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3100 IWineD3DDevice *iface,
3101 UINT start,
3102 CONST float *srcData,
3103 UINT count) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 UINT i;
3108 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3109 iface, srcData, start, count);
3111 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3112 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3113 return WINED3DERR_INVALIDCALL;
3115 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3116 if(TRACE_ON(d3d)) {
3117 for (i = 0; i < count; i++)
3118 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3119 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3122 if (!This->isRecordingState)
3124 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3128 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3129 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3131 return WINED3D_OK;
3134 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3135 IWineD3DDevice *iface,
3136 UINT start,
3137 float *dstData,
3138 UINT count) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 int cnt = min(count, This->d3d_vshader_constantF - start);
3143 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3144 iface, dstData, start, count);
3146 if (dstData == NULL || cnt < 0)
3147 return WINED3DERR_INVALIDCALL;
3149 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3150 return WINED3D_OK;
3153 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3154 DWORD i;
3155 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3161 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3163 DWORD i = This->rev_tex_unit_map[unit];
3164 DWORD j = This->texUnitMap[stage];
3166 This->texUnitMap[stage] = unit;
3167 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3169 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3172 This->rev_tex_unit_map[unit] = stage;
3173 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3175 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3179 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3180 int i;
3182 This->fixed_function_usage_map = 0;
3183 for (i = 0; i < MAX_TEXTURES; ++i) {
3184 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3185 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3186 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3187 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3188 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3189 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3190 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3191 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3193 if (color_op == WINED3DTOP_DISABLE) {
3194 /* Not used, and disable higher stages */
3195 break;
3198 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3199 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3200 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3201 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3202 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3203 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3204 This->fixed_function_usage_map |= (1 << i);
3207 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3208 This->fixed_function_usage_map |= (1 << (i + 1));
3213 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3215 unsigned int i, tex;
3216 WORD ffu_map;
3218 device_update_fixed_function_usage_map(This);
3219 ffu_map = This->fixed_function_usage_map;
3221 if (This->max_ffp_textures == gl_info->limits.texture_stages
3222 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3224 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3226 if (!(ffu_map & 1)) continue;
3228 if (This->texUnitMap[i] != i) {
3229 device_map_stage(This, i, i);
3230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3231 markTextureStagesDirty(This, i);
3234 return;
3237 /* Now work out the mapping */
3238 tex = 0;
3239 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3241 if (!(ffu_map & 1)) continue;
3243 if (This->texUnitMap[i] != tex) {
3244 device_map_stage(This, i, tex);
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3246 markTextureStagesDirty(This, i);
3249 ++tex;
3253 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3255 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3256 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3257 unsigned int i;
3259 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3260 if (sampler_type[i] && This->texUnitMap[i] != i)
3262 device_map_stage(This, i, i);
3263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3264 if (i < gl_info->limits.texture_stages)
3266 markTextureStagesDirty(This, i);
3272 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3273 const DWORD *vshader_sampler_tokens, DWORD unit)
3275 DWORD current_mapping = This->rev_tex_unit_map[unit];
3277 /* Not currently used */
3278 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3280 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3281 /* Used by a fragment sampler */
3283 if (!pshader_sampler_tokens) {
3284 /* No pixel shader, check fixed function */
3285 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3288 /* Pixel shader, check the shader's sampler map */
3289 return !pshader_sampler_tokens[current_mapping];
3292 /* Used by a vertex sampler */
3293 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3296 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3298 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3299 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3300 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3301 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3302 int i;
3304 if (ps) {
3305 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3307 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3308 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3309 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3312 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3313 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3314 if (vshader_sampler_type[i])
3316 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3318 /* Already mapped somewhere */
3319 continue;
3322 while (start >= 0) {
3323 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3325 device_map_stage(This, vsampler_idx, start);
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3328 --start;
3329 break;
3332 --start;
3338 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3340 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3341 BOOL vs = use_vs(This->stateBlock);
3342 BOOL ps = use_ps(This->stateBlock);
3344 * Rules are:
3345 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3346 * that would be really messy and require shader recompilation
3347 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3348 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3350 if (ps) device_map_psamplers(This, gl_info);
3351 else device_map_fixed_function_samplers(This, gl_info);
3353 if (vs) device_map_vsamplers(This, ps, gl_info);
3356 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3359 This->updateStateBlock->pixelShader = pShader;
3360 This->updateStateBlock->changed.pixelShader = TRUE;
3362 /* Handle recording of state blocks */
3363 if (This->isRecordingState) {
3364 TRACE("Recording... not performing anything\n");
3367 if (This->isRecordingState) {
3368 TRACE("Recording... not performing anything\n");
3369 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3370 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3371 return WINED3D_OK;
3374 if(pShader == oldShader) {
3375 TRACE("App is setting the old pixel shader over, nothing to do\n");
3376 return WINED3D_OK;
3379 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3380 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3382 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3385 return WINED3D_OK;
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 if (NULL == ppShader) {
3392 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3393 return WINED3DERR_INVALIDCALL;
3396 *ppShader = This->stateBlock->pixelShader;
3397 if (NULL != *ppShader) {
3398 IWineD3DPixelShader_AddRef(*ppShader);
3400 TRACE("(%p) : returning %p\n", This, *ppShader);
3401 return WINED3D_OK;
3404 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3405 IWineD3DDevice *iface,
3406 UINT start,
3407 CONST BOOL *srcData,
3408 UINT count) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3413 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3414 iface, srcData, start, count);
3416 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3418 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3419 for (i = 0; i < cnt; i++)
3420 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3422 for (i = start; i < cnt + start; ++i) {
3423 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3426 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3428 return WINED3D_OK;
3431 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3432 IWineD3DDevice *iface,
3433 UINT start,
3434 BOOL *dstData,
3435 UINT count) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3438 int cnt = min(count, MAX_CONST_B - start);
3440 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3441 iface, dstData, start, count);
3443 if (dstData == NULL || cnt < 0)
3444 return WINED3DERR_INVALIDCALL;
3446 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3447 return WINED3D_OK;
3450 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3451 IWineD3DDevice *iface,
3452 UINT start,
3453 CONST int *srcData,
3454 UINT count) {
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3457 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3459 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3460 iface, srcData, start, count);
3462 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3464 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3465 for (i = 0; i < cnt; i++)
3466 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3467 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3469 for (i = start; i < cnt + start; ++i) {
3470 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3473 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3475 return WINED3D_OK;
3478 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3479 IWineD3DDevice *iface,
3480 UINT start,
3481 int *dstData,
3482 UINT count) {
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3485 int cnt = min(count, MAX_CONST_I - start);
3487 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3488 iface, dstData, start, count);
3490 if (dstData == NULL || cnt < 0)
3491 return WINED3DERR_INVALIDCALL;
3493 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3494 return WINED3D_OK;
3497 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3498 IWineD3DDevice *iface,
3499 UINT start,
3500 CONST float *srcData,
3501 UINT count) {
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 UINT i;
3506 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3507 iface, srcData, start, count);
3509 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3510 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3511 return WINED3DERR_INVALIDCALL;
3513 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3514 if(TRACE_ON(d3d)) {
3515 for (i = 0; i < count; i++)
3516 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3517 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3520 if (!This->isRecordingState)
3522 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3526 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3527 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3529 return WINED3D_OK;
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3533 IWineD3DDevice *iface,
3534 UINT start,
3535 float *dstData,
3536 UINT count) {
3538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3539 int cnt = min(count, This->d3d_pshader_constantF - start);
3541 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3542 iface, dstData, start, count);
3544 if (dstData == NULL || cnt < 0)
3545 return WINED3DERR_INVALIDCALL;
3547 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3548 return WINED3D_OK;
3551 /* Context activation is done by the caller. */
3552 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3553 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3554 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3555 DWORD DestFVF)
3557 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3558 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3559 unsigned int i;
3560 WINED3DVIEWPORT vp;
3561 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3562 BOOL doClip;
3563 DWORD numTextures;
3565 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3567 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3570 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3572 ERR("Source has no position mask\n");
3573 return WINED3DERR_INVALIDCALL;
3576 /* We might access VBOs from this code, so hold the lock */
3577 ENTER_GL();
3579 if (!dest->resource.allocatedMemory)
3580 buffer_get_sysmem(dest, gl_info);
3582 /* Get a pointer into the destination vbo(create one if none exists) and
3583 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3585 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3587 dest->flags |= WINED3D_BUFFER_CREATEBO;
3588 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3591 if (dest->buffer_object)
3593 unsigned char extrabytes = 0;
3594 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3595 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3596 * this may write 4 extra bytes beyond the area that should be written
3598 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3599 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3600 if(!dest_conv_addr) {
3601 ERR("Out of memory\n");
3602 /* Continue without storing converted vertices */
3604 dest_conv = dest_conv_addr;
3607 /* Should I clip?
3608 * a) WINED3DRS_CLIPPING is enabled
3609 * b) WINED3DVOP_CLIP is passed
3611 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3612 static BOOL warned = FALSE;
3614 * The clipping code is not quite correct. Some things need
3615 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3616 * so disable clipping for now.
3617 * (The graphics in Half-Life are broken, and my processvertices
3618 * test crashes with IDirect3DDevice3)
3619 doClip = TRUE;
3621 doClip = FALSE;
3622 if(!warned) {
3623 warned = TRUE;
3624 FIXME("Clipping is broken and disabled for now\n");
3626 } else doClip = FALSE;
3627 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3629 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3630 WINED3DTS_VIEW,
3631 &view_mat);
3632 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3633 WINED3DTS_PROJECTION,
3634 &proj_mat);
3635 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3636 WINED3DTS_WORLDMATRIX(0),
3637 &world_mat);
3639 TRACE("View mat:\n");
3640 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);
3641 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);
3642 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);
3643 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);
3645 TRACE("Proj mat:\n");
3646 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);
3647 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);
3648 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);
3649 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);
3651 TRACE("World mat:\n");
3652 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);
3653 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);
3654 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);
3655 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);
3657 /* Get the viewport */
3658 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3659 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3660 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3662 multiply_matrix(&mat,&view_mat,&world_mat);
3663 multiply_matrix(&mat,&proj_mat,&mat);
3665 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3667 for (i = 0; i < dwCount; i+= 1) {
3668 unsigned int tex_index;
3670 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3671 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3672 /* The position first */
3673 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3674 const float *p = (const float *)(element->data + i * element->stride);
3675 float x, y, z, rhw;
3676 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3678 /* Multiplication with world, view and projection matrix */
3679 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);
3680 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);
3681 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);
3682 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);
3684 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3686 /* WARNING: The following things are taken from d3d7 and were not yet checked
3687 * against d3d8 or d3d9!
3690 /* Clipping conditions: From msdn
3692 * A vertex is clipped if it does not match the following requirements
3693 * -rhw < x <= rhw
3694 * -rhw < y <= rhw
3695 * 0 < z <= rhw
3696 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3698 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3699 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3703 if( !doClip ||
3704 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3705 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3706 ( rhw > eps ) ) ) {
3708 /* "Normal" viewport transformation (not clipped)
3709 * 1) The values are divided by rhw
3710 * 2) The y axis is negative, so multiply it with -1
3711 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3712 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3713 * 4) Multiply x with Width/2 and add Width/2
3714 * 5) The same for the height
3715 * 6) Add the viewpoint X and Y to the 2D coordinates and
3716 * The minimum Z value to z
3717 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3719 * Well, basically it's simply a linear transformation into viewport
3720 * coordinates
3723 x /= rhw;
3724 y /= rhw;
3725 z /= rhw;
3727 y *= -1;
3729 x *= vp.Width / 2;
3730 y *= vp.Height / 2;
3731 z *= vp.MaxZ - vp.MinZ;
3733 x += vp.Width / 2 + vp.X;
3734 y += vp.Height / 2 + vp.Y;
3735 z += vp.MinZ;
3737 rhw = 1 / rhw;
3738 } else {
3739 /* That vertex got clipped
3740 * Contrary to OpenGL it is not dropped completely, it just
3741 * undergoes a different calculation.
3743 TRACE("Vertex got clipped\n");
3744 x += rhw;
3745 y += rhw;
3747 x /= 2;
3748 y /= 2;
3750 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3751 * outside of the main vertex buffer memory. That needs some more
3752 * investigation...
3756 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3759 ( (float *) dest_ptr)[0] = x;
3760 ( (float *) dest_ptr)[1] = y;
3761 ( (float *) dest_ptr)[2] = z;
3762 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3764 dest_ptr += 3 * sizeof(float);
3766 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3767 dest_ptr += sizeof(float);
3770 if(dest_conv) {
3771 float w = 1 / rhw;
3772 ( (float *) dest_conv)[0] = x * w;
3773 ( (float *) dest_conv)[1] = y * w;
3774 ( (float *) dest_conv)[2] = z * w;
3775 ( (float *) dest_conv)[3] = w;
3777 dest_conv += 3 * sizeof(float);
3779 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3780 dest_conv += sizeof(float);
3784 if (DestFVF & WINED3DFVF_PSIZE) {
3785 dest_ptr += sizeof(DWORD);
3786 if(dest_conv) dest_conv += sizeof(DWORD);
3788 if (DestFVF & WINED3DFVF_NORMAL) {
3789 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3790 const float *normal = (const float *)(element->data + i * element->stride);
3791 /* AFAIK this should go into the lighting information */
3792 FIXME("Didn't expect the destination to have a normal\n");
3793 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3794 if(dest_conv) {
3795 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3799 if (DestFVF & WINED3DFVF_DIFFUSE) {
3800 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3801 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3802 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3804 static BOOL warned = FALSE;
3806 if(!warned) {
3807 ERR("No diffuse color in source, but destination has one\n");
3808 warned = TRUE;
3811 *( (DWORD *) dest_ptr) = 0xffffffff;
3812 dest_ptr += sizeof(DWORD);
3814 if(dest_conv) {
3815 *( (DWORD *) dest_conv) = 0xffffffff;
3816 dest_conv += sizeof(DWORD);
3819 else {
3820 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3821 if(dest_conv) {
3822 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3823 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3824 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3825 dest_conv += sizeof(DWORD);
3830 if (DestFVF & WINED3DFVF_SPECULAR)
3832 /* What's the color value in the feedback buffer? */
3833 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3834 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3835 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3837 static BOOL warned = FALSE;
3839 if(!warned) {
3840 ERR("No specular color in source, but destination has one\n");
3841 warned = TRUE;
3844 *( (DWORD *) dest_ptr) = 0xFF000000;
3845 dest_ptr += sizeof(DWORD);
3847 if(dest_conv) {
3848 *( (DWORD *) dest_conv) = 0xFF000000;
3849 dest_conv += sizeof(DWORD);
3852 else {
3853 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3854 if(dest_conv) {
3855 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3856 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3857 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3858 dest_conv += sizeof(DWORD);
3863 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3864 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3865 const float *tex_coord = (const float *)(element->data + i * element->stride);
3866 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3868 ERR("No source texture, but destination requests one\n");
3869 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3870 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3872 else {
3873 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3874 if(dest_conv) {
3875 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3881 if(dest_conv) {
3882 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3883 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3884 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3885 dwCount * get_flexible_vertex_size(DestFVF),
3886 dest_conv_addr));
3887 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3888 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3891 LEAVE_GL();
3893 return WINED3D_OK;
3895 #undef copy_and_next
3897 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3898 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3899 DWORD DestFVF)
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 struct wined3d_stream_info stream_info;
3903 const struct wined3d_gl_info *gl_info;
3904 struct wined3d_context *context;
3905 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3906 HRESULT hr;
3908 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3910 if(pVertexDecl) {
3911 ERR("Output vertex declaration not implemented yet\n");
3914 /* Need any context to write to the vbo. */
3915 context = context_acquire(This, NULL);
3916 gl_info = context->gl_info;
3918 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3919 * control the streamIsUP flag, thus restore it afterwards.
3921 This->stateBlock->streamIsUP = FALSE;
3922 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3923 This->stateBlock->streamIsUP = streamWasUP;
3925 if(vbo || SrcStartIndex) {
3926 unsigned int i;
3927 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3928 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3930 * Also get the start index in, but only loop over all elements if there's something to add at all.
3932 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3934 struct wined3d_stream_info_element *e;
3936 if (!(stream_info.use_map & (1 << i))) continue;
3938 e = &stream_info.elements[i];
3939 if (e->buffer_object)
3941 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3942 e->buffer_object = 0;
3943 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3944 ENTER_GL();
3945 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3946 vb->buffer_object = 0;
3947 LEAVE_GL();
3949 if (e->data) e->data += e->stride * SrcStartIndex;
3953 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3954 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3956 context_release(context);
3958 return hr;
3961 /*****
3962 * Get / Set Texture Stage States
3963 * TODO: Verify against dx9 definitions
3964 *****/
3965 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3967 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3968 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3970 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3972 if (Stage >= gl_info->limits.texture_stages)
3974 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3975 Stage, gl_info->limits.texture_stages - 1);
3976 return WINED3D_OK;
3979 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3980 This->updateStateBlock->textureState[Stage][Type] = Value;
3982 if (This->isRecordingState) {
3983 TRACE("Recording... not performing anything\n");
3984 return WINED3D_OK;
3987 /* Checked after the assignments to allow proper stateblock recording */
3988 if(oldValue == Value) {
3989 TRACE("App is setting the old value over, nothing to do\n");
3990 return WINED3D_OK;
3993 if(Stage > This->stateBlock->lowest_disabled_stage &&
3994 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3995 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3996 * Changes in other states are important on disabled stages too
3998 return WINED3D_OK;
4001 if(Type == WINED3DTSS_COLOROP) {
4002 unsigned int i;
4004 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4005 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4006 * they have to be disabled
4008 * The current stage is dirtified below.
4010 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4011 TRACE("Additionally dirtifying stage %u\n", i);
4012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4014 This->stateBlock->lowest_disabled_stage = Stage;
4015 TRACE("New lowest disabled: %u\n", Stage);
4016 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4017 /* Previously disabled stage enabled. Stages above it may need enabling
4018 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4019 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4021 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4024 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4026 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4027 break;
4029 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4032 This->stateBlock->lowest_disabled_stage = i;
4033 TRACE("New lowest disabled: %u\n", i);
4037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4039 return WINED3D_OK;
4042 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4044 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4045 *pValue = This->updateStateBlock->textureState[Stage][Type];
4046 return WINED3D_OK;
4049 /*****
4050 * Get / Set Texture
4051 *****/
4052 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4053 DWORD stage, IWineD3DBaseTexture *texture)
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4056 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4057 IWineD3DBaseTexture *prev;
4059 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4061 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4062 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4064 /* Windows accepts overflowing this array... we do not. */
4065 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4067 WARN("Ignoring invalid stage %u.\n", stage);
4068 return WINED3D_OK;
4071 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4072 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4074 WARN("Rejecting attempt to set scratch texture.\n");
4075 return WINED3DERR_INVALIDCALL;
4078 This->updateStateBlock->changed.textures |= 1 << stage;
4080 prev = This->updateStateBlock->textures[stage];
4081 TRACE("Previous texture %p.\n", prev);
4083 if (texture == prev)
4085 TRACE("App is setting the same texture again, nothing to do.\n");
4086 return WINED3D_OK;
4089 TRACE("Setting new texture to %p.\n", texture);
4090 This->updateStateBlock->textures[stage] = texture;
4092 if (This->isRecordingState)
4094 TRACE("Recording... not performing anything\n");
4096 if (texture) IWineD3DBaseTexture_AddRef(texture);
4097 if (prev) IWineD3DBaseTexture_Release(prev);
4099 return WINED3D_OK;
4102 if (texture)
4104 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4105 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4106 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4108 IWineD3DBaseTexture_AddRef(texture);
4110 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4115 if (!prev && stage < gl_info->limits.texture_stages)
4117 /* The source arguments for color and alpha ops have different
4118 * meanings when a NULL texture is bound, so the COLOROP and
4119 * ALPHAOP have to be dirtified. */
4120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4124 if (bind_count == 1) t->baseTexture.sampler = stage;
4127 if (prev)
4129 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4130 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4132 IWineD3DBaseTexture_Release(prev);
4134 if (!texture && stage < gl_info->limits.texture_stages)
4136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4140 if (bind_count && t->baseTexture.sampler == stage)
4142 unsigned int i;
4144 /* Search for other stages the texture is bound to. Shouldn't
4145 * happen if applications bind textures to a single stage only. */
4146 TRACE("Searching for other stages the texture is bound to.\n");
4147 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4149 if (This->updateStateBlock->textures[i] == prev)
4151 TRACE("Texture is also bound to stage %u.\n", i);
4152 t->baseTexture.sampler = i;
4153 break;
4159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4161 return WINED3D_OK;
4164 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4167 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4169 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4170 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4173 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4174 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4175 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4178 *ppTexture=This->stateBlock->textures[Stage];
4179 if (*ppTexture)
4180 IWineD3DBaseTexture_AddRef(*ppTexture);
4182 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4184 return WINED3D_OK;
4187 /*****
4188 * Get Back Buffer
4189 *****/
4190 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4191 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4193 IWineD3DSwapChain *swapchain;
4194 HRESULT hr;
4196 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4197 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4199 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4200 if (FAILED(hr))
4202 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4203 return hr;
4206 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4207 IWineD3DSwapChain_Release(swapchain);
4208 if (FAILED(hr))
4210 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4211 return hr;
4214 return WINED3D_OK;
4217 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4219 WARN("(%p) : stub, calling idirect3d for now\n", This);
4220 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4223 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4225 IWineD3DSwapChain *swapChain;
4226 HRESULT hr;
4228 if(iSwapChain > 0) {
4229 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4230 if (hr == WINED3D_OK) {
4231 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4232 IWineD3DSwapChain_Release(swapChain);
4233 } else {
4234 FIXME("(%p) Error getting display mode\n", This);
4236 } else {
4237 /* Don't read the real display mode,
4238 but return the stored mode instead. X11 can't change the color
4239 depth, and some apps are pretty angry if they SetDisplayMode from
4240 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4242 Also don't relay to the swapchain because with ddraw it's possible
4243 that there isn't a swapchain at all */
4244 pMode->Width = This->ddraw_width;
4245 pMode->Height = This->ddraw_height;
4246 pMode->Format = This->ddraw_format;
4247 pMode->RefreshRate = 0;
4248 hr = WINED3D_OK;
4251 return hr;
4254 /*****
4255 * Stateblock related functions
4256 *****/
4258 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4260 IWineD3DStateBlock *stateblock;
4261 HRESULT hr;
4263 TRACE("(%p)\n", This);
4265 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4267 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4268 if (FAILED(hr)) return hr;
4270 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4271 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4272 This->isRecordingState = TRUE;
4274 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4276 return WINED3D_OK;
4279 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4281 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4283 if (!This->isRecordingState) {
4284 WARN("(%p) not recording! returning error\n", This);
4285 *ppStateBlock = NULL;
4286 return WINED3DERR_INVALIDCALL;
4289 stateblock_init_contained_states(object);
4291 *ppStateBlock = (IWineD3DStateBlock*) object;
4292 This->isRecordingState = FALSE;
4293 This->updateStateBlock = This->stateBlock;
4294 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4295 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4296 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4297 return WINED3D_OK;
4300 /*****
4301 * Scene related functions
4302 *****/
4303 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4304 /* At the moment we have no need for any functionality at the beginning
4305 of a scene */
4306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4307 TRACE("(%p)\n", This);
4309 if(This->inScene) {
4310 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4311 return WINED3DERR_INVALIDCALL;
4313 This->inScene = TRUE;
4314 return WINED3D_OK;
4317 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4320 struct wined3d_context *context;
4322 TRACE("(%p)\n", This);
4324 if(!This->inScene) {
4325 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4326 return WINED3DERR_INVALIDCALL;
4329 context = context_acquire(This, NULL);
4330 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4331 wglFlush();
4332 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4333 * fails. */
4334 context_release(context);
4336 This->inScene = FALSE;
4337 return WINED3D_OK;
4340 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4341 const RECT *pSourceRect, const RECT *pDestRect,
4342 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4344 IWineD3DSwapChain *swapChain = NULL;
4345 int i;
4346 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4348 TRACE("iface %p.\n", iface);
4350 for(i = 0 ; i < swapchains ; i ++) {
4352 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4353 TRACE("presentinng chain %d, %p\n", i, swapChain);
4354 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4355 IWineD3DSwapChain_Release(swapChain);
4358 return WINED3D_OK;
4361 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
4363 /* partial draw rect */
4364 if (draw_rect->left || draw_rect->top
4365 || draw_rect->right < target->currentDesc.Width
4366 || draw_rect->bottom < target->currentDesc.Height)
4367 return FALSE;
4369 /* partial clear rect */
4370 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
4371 || clear_rect->right < target->currentDesc.Width
4372 || clear_rect->bottom < target->currentDesc.Height))
4373 return FALSE;
4375 return TRUE;
4378 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
4379 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
4381 RECT current_rect, r;
4383 if (ds->Flags & location)
4384 SetRect(&current_rect, 0, 0,
4385 ds->ds_current_size.cx,
4386 ds->ds_current_size.cy);
4387 else
4388 SetRectEmpty(&current_rect);
4390 IntersectRect(&r, draw_rect, &current_rect);
4391 if (EqualRect(&r, draw_rect))
4393 /* current_rect ⊇ draw_rect, modify only. */
4394 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4395 return;
4398 if (EqualRect(&r, &current_rect))
4400 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
4402 if (!clear_rect)
4404 /* Full clear, modify only. */
4405 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4406 return;
4409 IntersectRect(&r, draw_rect, clear_rect);
4410 if (EqualRect(&r, draw_rect))
4412 /* clear_rect ⊇ draw_rect, modify only. */
4413 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4414 return;
4418 /* Full load. */
4419 surface_load_ds_location(ds, context, location);
4420 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4423 /* Not called from the VTable (internal subroutine) */
4424 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4425 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4427 const RECT *clear_rect = (Count > 0 && pRects) ? (const RECT *)pRects : NULL;
4428 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4429 GLbitfield glMask = 0;
4430 unsigned int i;
4431 UINT drawable_width, drawable_height;
4432 struct wined3d_context *context;
4433 RECT draw_rect;
4435 device_get_draw_rect(This, &draw_rect);
4437 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4438 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4439 * for the cleared parts, and the untouched parts.
4441 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4442 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4443 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4444 * checking all this if the dest surface is in the drawable anyway.
4446 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4448 if (!is_full_clear(target, &draw_rect, clear_rect))
4449 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4452 context = context_acquire(This, target);
4453 if (!context->valid)
4455 context_release(context);
4456 WARN("Invalid context, skipping clear.\n");
4457 return WINED3D_OK;
4460 context_apply_clear_state(context, This, target, depth_stencil);
4462 target->get_drawable_size(context, &drawable_width, &drawable_height);
4464 ENTER_GL();
4466 /* Only set the values up once, as they are not changing */
4467 if (Flags & WINED3DCLEAR_STENCIL)
4469 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4471 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4474 glStencilMask(~0U);
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4476 glClearStencil(Stencil);
4477 checkGLcall("glClearStencil");
4478 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4481 if (Flags & WINED3DCLEAR_ZBUFFER)
4483 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4485 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4486 device_switch_onscreen_ds(This, context, depth_stencil);
4487 prepare_ds_clear(depth_stencil, context, location, &draw_rect, Count, clear_rect);
4488 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)depth_stencil, SFLAG_INDRAWABLE, TRUE);
4490 glDepthMask(GL_TRUE);
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4492 glClearDepth(Z);
4493 checkGLcall("glClearDepth");
4494 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4497 if (Flags & WINED3DCLEAR_TARGET)
4499 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4501 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4506 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4507 checkGLcall("glClearColor");
4508 glMask = glMask | GL_COLOR_BUFFER_BIT;
4511 if (!clear_rect)
4513 if (context->render_offscreen)
4515 glScissor(draw_rect.left, draw_rect.top,
4516 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4518 else
4520 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
4521 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4523 checkGLcall("glScissor");
4524 glClear(glMask);
4525 checkGLcall("glClear");
4527 else
4529 RECT current_rect;
4531 /* Now process each rect in turn. */
4532 for (i = 0; i < Count; ++i)
4534 /* Note gl uses lower left, width/height */
4535 IntersectRect(&current_rect, &draw_rect, &clear_rect[i]);
4537 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
4538 wine_dbgstr_rect(&clear_rect[i]),
4539 wine_dbgstr_rect(&current_rect));
4541 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4542 * The rectangle is not cleared, no error is returned, but further rectanlges are
4543 * still cleared if they are valid. */
4544 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
4546 TRACE("Rectangle with negative dimensions, ignoring.\n");
4547 continue;
4550 if (context->render_offscreen)
4552 glScissor(current_rect.left, current_rect.top,
4553 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4555 else
4557 glScissor(current_rect.left, drawable_height - current_rect.bottom,
4558 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4560 checkGLcall("glScissor");
4562 glClear(glMask);
4563 checkGLcall("glClear");
4567 LEAVE_GL();
4569 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4570 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4571 wglFlush(); /* Flush to ensure ordering across contexts. */
4573 context_release(context);
4575 return WINED3D_OK;
4578 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4579 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4584 Count, pRects, Flags, Color, Z, Stencil);
4586 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4588 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4589 /* TODO: What about depth stencil buffers without stencil bits? */
4590 return WINED3DERR_INVALIDCALL;
4593 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4596 /*****
4597 * Drawing functions
4598 *****/
4600 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4601 WINED3DPRIMITIVETYPE primitive_type)
4603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4605 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4607 This->updateStateBlock->changed.primitive_type = TRUE;
4608 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4611 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4612 WINED3DPRIMITIVETYPE *primitive_type)
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4618 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4620 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4623 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4629 if(!This->stateBlock->vertexDecl) {
4630 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4631 return WINED3DERR_INVALIDCALL;
4634 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4635 if(This->stateBlock->streamIsUP) {
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4637 This->stateBlock->streamIsUP = FALSE;
4640 if(This->stateBlock->loadBaseVertexIndex != 0) {
4641 This->stateBlock->loadBaseVertexIndex = 0;
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4644 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4645 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4646 return WINED3D_OK;
4649 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4652 UINT idxStride = 2;
4653 IWineD3DBuffer *pIB;
4654 GLuint vbo;
4656 pIB = This->stateBlock->pIndexData;
4657 if (!pIB) {
4658 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4659 * without an index buffer set. (The first time at least...)
4660 * D3D8 simply dies, but I doubt it can do much harm to return
4661 * D3DERR_INVALIDCALL there as well. */
4662 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4663 return WINED3DERR_INVALIDCALL;
4666 if(!This->stateBlock->vertexDecl) {
4667 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4668 return WINED3DERR_INVALIDCALL;
4671 if(This->stateBlock->streamIsUP) {
4672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4673 This->stateBlock->streamIsUP = FALSE;
4675 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4677 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4679 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4680 idxStride = 2;
4681 } else {
4682 idxStride = 4;
4685 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4686 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4690 drawPrimitive(iface, index_count, startIndex, idxStride,
4691 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4693 return WINED3D_OK;
4696 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4697 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4700 IWineD3DBuffer *vb;
4702 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4703 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4705 if(!This->stateBlock->vertexDecl) {
4706 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4707 return WINED3DERR_INVALIDCALL;
4710 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4711 vb = This->stateBlock->streamSource[0];
4712 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4713 if (vb) IWineD3DBuffer_Release(vb);
4714 This->stateBlock->streamOffset[0] = 0;
4715 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4716 This->stateBlock->streamIsUP = TRUE;
4717 This->stateBlock->loadBaseVertexIndex = 0;
4719 /* TODO: Only mark dirty if drawing from a different UP address */
4720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4722 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4724 /* MSDN specifies stream zero settings must be set to NULL */
4725 This->stateBlock->streamStride[0] = 0;
4726 This->stateBlock->streamSource[0] = NULL;
4728 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4729 * the new stream sources or use UP drawing again
4731 return WINED3D_OK;
4734 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4735 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4736 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4738 int idxStride;
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 IWineD3DBuffer *vb;
4741 IWineD3DBuffer *ib;
4743 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4744 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4746 if(!This->stateBlock->vertexDecl) {
4747 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4748 return WINED3DERR_INVALIDCALL;
4751 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4752 idxStride = 2;
4753 } else {
4754 idxStride = 4;
4757 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4758 vb = This->stateBlock->streamSource[0];
4759 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4760 if (vb) IWineD3DBuffer_Release(vb);
4761 This->stateBlock->streamIsUP = TRUE;
4762 This->stateBlock->streamOffset[0] = 0;
4763 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4765 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4766 This->stateBlock->baseVertexIndex = 0;
4767 This->stateBlock->loadBaseVertexIndex = 0;
4768 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4772 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4774 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4775 This->stateBlock->streamSource[0] = NULL;
4776 This->stateBlock->streamStride[0] = 0;
4777 ib = This->stateBlock->pIndexData;
4778 if(ib) {
4779 IWineD3DBuffer_Release(ib);
4780 This->stateBlock->pIndexData = NULL;
4782 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4783 * SetStreamSource to specify a vertex buffer
4786 return WINED3D_OK;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4790 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4794 /* Mark the state dirty until we have nicer tracking
4795 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4796 * that value.
4798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4800 This->stateBlock->baseVertexIndex = 0;
4801 This->up_strided = DrawPrimStrideData;
4802 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4803 This->up_strided = NULL;
4804 return WINED3D_OK;
4807 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4808 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4809 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4812 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4814 /* Mark the state dirty until we have nicer tracking
4815 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4816 * that value.
4818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4820 This->stateBlock->streamIsUP = TRUE;
4821 This->stateBlock->baseVertexIndex = 0;
4822 This->up_strided = DrawPrimStrideData;
4823 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4824 This->up_strided = NULL;
4825 return WINED3D_OK;
4828 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4829 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4830 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4832 WINED3DLOCKED_BOX src;
4833 WINED3DLOCKED_BOX dst;
4834 HRESULT hr;
4836 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4837 iface, pSourceVolume, pDestinationVolume);
4839 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4840 * dirtification to improve loading performance.
4842 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4843 if(FAILED(hr)) return hr;
4844 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4845 if(FAILED(hr)) {
4846 IWineD3DVolume_UnlockBox(pSourceVolume);
4847 return hr;
4850 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4852 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4853 if(FAILED(hr)) {
4854 IWineD3DVolume_UnlockBox(pSourceVolume);
4855 } else {
4856 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4858 return hr;
4861 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4862 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4864 unsigned int level_count, i;
4865 WINED3DRESOURCETYPE type;
4866 HRESULT hr;
4868 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4870 /* Verify that the source and destination textures are non-NULL. */
4871 if (!src_texture || !dst_texture)
4873 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4874 return WINED3DERR_INVALIDCALL;
4877 if (src_texture == dst_texture)
4879 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4880 return WINED3DERR_INVALIDCALL;
4883 /* Verify that the source and destination textures are the same type. */
4884 type = IWineD3DBaseTexture_GetType(src_texture);
4885 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4887 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4888 return WINED3DERR_INVALIDCALL;
4891 /* Check that both textures have the identical numbers of levels. */
4892 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4893 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4895 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4896 return WINED3DERR_INVALIDCALL;
4899 /* Make sure that the destination texture is loaded. */
4900 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4902 /* Update every surface level of the texture. */
4903 switch (type)
4905 case WINED3DRTYPE_TEXTURE:
4907 IWineD3DSurface *src_surface;
4908 IWineD3DSurface *dst_surface;
4910 for (i = 0; i < level_count; ++i)
4912 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4913 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4914 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4915 IWineD3DSurface_Release(dst_surface);
4916 IWineD3DSurface_Release(src_surface);
4917 if (FAILED(hr))
4919 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4920 return hr;
4923 break;
4926 case WINED3DRTYPE_CUBETEXTURE:
4928 IWineD3DSurface *src_surface;
4929 IWineD3DSurface *dst_surface;
4930 WINED3DCUBEMAP_FACES face;
4932 for (i = 0; i < level_count; ++i)
4934 /* Update each cube face. */
4935 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4937 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4938 face, i, &src_surface);
4939 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4940 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4941 face, i, &dst_surface);
4942 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4943 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4944 IWineD3DSurface_Release(dst_surface);
4945 IWineD3DSurface_Release(src_surface);
4946 if (FAILED(hr))
4948 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4949 return hr;
4953 break;
4956 case WINED3DRTYPE_VOLUMETEXTURE:
4958 IWineD3DVolume *src_volume;
4959 IWineD3DVolume *dst_volume;
4961 for (i = 0; i < level_count; ++i)
4963 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4964 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4965 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4966 IWineD3DVolume_Release(dst_volume);
4967 IWineD3DVolume_Release(src_volume);
4968 if (FAILED(hr))
4970 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4971 return hr;
4974 break;
4977 default:
4978 FIXME("Unsupported texture type %#x.\n", type);
4979 return WINED3DERR_INVALIDCALL;
4982 return WINED3D_OK;
4985 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4986 IWineD3DSwapChain *swapChain;
4987 HRESULT hr;
4988 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4989 if(hr == WINED3D_OK) {
4990 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4991 IWineD3DSwapChain_Release(swapChain);
4993 return hr;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 IWineD3DBaseTextureImpl *texture;
4999 DWORD i;
5001 TRACE("(%p) : %p\n", This, pNumPasses);
5003 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5004 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5005 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5006 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5008 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5009 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5010 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5013 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5014 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5016 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5017 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5018 return E_FAIL;
5020 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5021 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5022 return E_FAIL;
5024 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5025 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5026 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5027 return E_FAIL;
5031 /* return a sensible default */
5032 *pNumPasses = 1;
5034 TRACE("returning D3D_OK\n");
5035 return WINED3D_OK;
5038 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5040 int i;
5042 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5044 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5045 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5046 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5048 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5053 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 int j;
5056 UINT NewSize;
5057 PALETTEENTRY **palettes;
5059 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5061 if (PaletteNumber >= MAX_PALETTES) {
5062 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5063 return WINED3DERR_INVALIDCALL;
5066 if (PaletteNumber >= This->NumberOfPalettes) {
5067 NewSize = This->NumberOfPalettes;
5068 do {
5069 NewSize *= 2;
5070 } while(PaletteNumber >= NewSize);
5071 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5072 if (!palettes) {
5073 ERR("Out of memory!\n");
5074 return E_OUTOFMEMORY;
5076 This->palettes = palettes;
5077 This->NumberOfPalettes = NewSize;
5080 if (!This->palettes[PaletteNumber]) {
5081 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5082 if (!This->palettes[PaletteNumber]) {
5083 ERR("Out of memory!\n");
5084 return E_OUTOFMEMORY;
5088 for (j = 0; j < 256; ++j) {
5089 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5090 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5091 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5092 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5094 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5095 TRACE("(%p) : returning\n", This);
5096 return WINED3D_OK;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5101 int j;
5102 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5103 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5104 /* What happens in such situation isn't documented; Native seems to silently abort
5105 on such conditions. Return Invalid Call. */
5106 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5107 return WINED3DERR_INVALIDCALL;
5109 for (j = 0; j < 256; ++j) {
5110 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5111 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5112 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5113 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5115 TRACE("(%p) : returning\n", This);
5116 return WINED3D_OK;
5119 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5121 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5122 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5123 (tested with reference rasterizer). Return Invalid Call. */
5124 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5125 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5126 return WINED3DERR_INVALIDCALL;
5128 /*TODO: stateblocks */
5129 if (This->currentPalette != PaletteNumber) {
5130 This->currentPalette = PaletteNumber;
5131 dirtify_p8_texture_samplers(This);
5133 TRACE("(%p) : returning\n", This);
5134 return WINED3D_OK;
5137 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5139 if (PaletteNumber == NULL) {
5140 WARN("(%p) : returning Invalid Call\n", This);
5141 return WINED3DERR_INVALIDCALL;
5143 /*TODO: stateblocks */
5144 *PaletteNumber = This->currentPalette;
5145 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5146 return WINED3D_OK;
5149 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 static BOOL warned;
5152 if (!warned)
5154 FIXME("(%p) : stub\n", This);
5155 warned = TRUE;
5158 This->softwareVertexProcessing = bSoftware;
5159 return WINED3D_OK;
5163 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165 static BOOL warned;
5166 if (!warned)
5168 FIXME("(%p) : stub\n", This);
5169 warned = TRUE;
5171 return This->softwareVertexProcessing;
5174 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5175 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5177 IWineD3DSwapChain *swapchain;
5178 HRESULT hr;
5180 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5181 iface, swapchain_idx, raster_status);
5183 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5184 if (FAILED(hr))
5186 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5187 return hr;
5190 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5191 IWineD3DSwapChain_Release(swapchain);
5192 if (FAILED(hr))
5194 WARN("Failed to get raster status, hr %#x.\n", hr);
5195 return hr;
5198 return WINED3D_OK;
5201 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5203 static BOOL warned;
5204 if(nSegments != 0.0f) {
5205 if (!warned)
5207 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5208 warned = TRUE;
5211 return WINED3D_OK;
5214 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5216 static BOOL warned;
5217 if (!warned)
5219 FIXME("iface %p stub!\n", iface);
5220 warned = TRUE;
5222 return 0.0f;
5225 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5226 IWineD3DSurface *src_surface, const RECT *src_rect,
5227 IWineD3DSurface *dst_surface, const POINT *dst_point)
5229 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5230 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 const struct wined3d_format_desc *src_format;
5233 const struct wined3d_format_desc *dst_format;
5234 const struct wined3d_gl_info *gl_info;
5235 struct wined3d_context *context;
5236 const unsigned char *data;
5237 UINT update_w, update_h;
5238 CONVERT_TYPES convert;
5239 UINT src_w, src_h;
5240 UINT dst_x, dst_y;
5241 DWORD sampler;
5242 struct wined3d_format_desc desc;
5244 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5245 iface, src_surface, wine_dbgstr_rect(src_rect),
5246 dst_surface, wine_dbgstr_point(dst_point));
5248 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5250 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5251 src_surface, dst_surface);
5252 return WINED3DERR_INVALIDCALL;
5255 src_format = src_impl->resource.format_desc;
5256 dst_format = dst_impl->resource.format_desc;
5258 if (src_format->format != dst_format->format)
5260 WARN("Source and destination surfaces should have the same format.\n");
5261 return WINED3DERR_INVALIDCALL;
5264 dst_x = dst_point ? dst_point->x : 0;
5265 dst_y = dst_point ? dst_point->y : 0;
5267 /* This call loads the OpenGL surface directly, instead of copying the
5268 * surface to the destination's sysmem copy. If surface conversion is
5269 * needed, use BltFast instead to copy in sysmem and use regular surface
5270 * loading. */
5271 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5272 if (convert != NO_CONVERSION || desc.convert)
5273 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5275 context = context_acquire(This, NULL);
5276 gl_info = context->gl_info;
5278 ENTER_GL();
5279 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5280 checkGLcall("glActiveTextureARB");
5281 LEAVE_GL();
5283 /* Make sure the surface is loaded and up to date */
5284 surface_internal_preload(dst_impl, SRGB_RGB);
5285 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5287 src_w = src_impl->currentDesc.Width;
5288 src_h = src_impl->currentDesc.Height;
5289 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5290 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5292 data = IWineD3DSurface_GetData(src_surface);
5293 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5295 ENTER_GL();
5297 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5299 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5300 UINT row_count = update_h / src_format->block_height;
5301 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5303 if (src_rect)
5305 data += (src_rect->top / src_format->block_height) * src_pitch;
5306 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5309 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5310 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5311 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5313 if (row_length == src_pitch)
5315 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5316 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5318 else
5320 UINT row, y;
5322 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5323 * can't use the unpack row length like below. */
5324 for (row = 0, y = dst_y; row < row_count; ++row)
5326 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5327 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5328 y += src_format->block_height;
5329 data += src_pitch;
5332 checkGLcall("glCompressedTexSubImage2DARB");
5334 else
5336 if (src_rect)
5338 data += src_rect->top * src_w * src_format->byte_count;
5339 data += src_rect->left * src_format->byte_count;
5342 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5343 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5344 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5346 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5347 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5348 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5349 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5350 checkGLcall("glTexSubImage2D");
5353 LEAVE_GL();
5354 context_release(context);
5356 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5357 sampler = This->rev_tex_unit_map[0];
5358 if (sampler != WINED3D_UNMAPPED_STAGE)
5360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5363 return WINED3D_OK;
5366 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 struct WineD3DRectPatch *patch;
5369 GLenum old_primitive_type;
5370 unsigned int i;
5371 struct list *e;
5372 BOOL found;
5373 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5375 if(!(Handle || pRectPatchInfo)) {
5376 /* TODO: Write a test for the return value, thus the FIXME */
5377 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5378 return WINED3DERR_INVALIDCALL;
5381 if(Handle) {
5382 i = PATCHMAP_HASHFUNC(Handle);
5383 found = FALSE;
5384 LIST_FOR_EACH(e, &This->patches[i]) {
5385 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5386 if(patch->Handle == Handle) {
5387 found = TRUE;
5388 break;
5392 if(!found) {
5393 TRACE("Patch does not exist. Creating a new one\n");
5394 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5395 patch->Handle = Handle;
5396 list_add_head(&This->patches[i], &patch->entry);
5397 } else {
5398 TRACE("Found existing patch %p\n", patch);
5400 } else {
5401 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5402 * attributes we have to tesselate, read back, and draw. This needs a patch
5403 * management structure instance. Create one.
5405 * A possible improvement is to check if a vertex shader is used, and if not directly
5406 * draw the patch.
5408 FIXME("Drawing an uncached patch. This is slow\n");
5409 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5412 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5413 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5414 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5415 HRESULT hr;
5416 TRACE("Tesselation density or patch info changed, retesselating\n");
5418 if(pRectPatchInfo) {
5419 patch->RectPatchInfo = *pRectPatchInfo;
5421 patch->numSegs[0] = pNumSegs[0];
5422 patch->numSegs[1] = pNumSegs[1];
5423 patch->numSegs[2] = pNumSegs[2];
5424 patch->numSegs[3] = pNumSegs[3];
5426 hr = tesselate_rectpatch(This, patch);
5427 if(FAILED(hr)) {
5428 WARN("Patch tesselation failed\n");
5430 /* Do not release the handle to store the params of the patch */
5431 if(!Handle) {
5432 HeapFree(GetProcessHeap(), 0, patch);
5434 return hr;
5438 This->currentPatch = patch;
5439 old_primitive_type = This->stateBlock->gl_primitive_type;
5440 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5441 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5442 This->stateBlock->gl_primitive_type = old_primitive_type;
5443 This->currentPatch = NULL;
5445 /* Destroy uncached patches */
5446 if(!Handle) {
5447 HeapFree(GetProcessHeap(), 0, patch->mem);
5448 HeapFree(GetProcessHeap(), 0, patch);
5450 return WINED3D_OK;
5453 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5454 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5456 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5457 iface, handle, segment_count, patch_info);
5459 return WINED3D_OK;
5462 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5464 int i;
5465 struct WineD3DRectPatch *patch;
5466 struct list *e;
5467 TRACE("(%p) Handle(%d)\n", This, Handle);
5469 i = PATCHMAP_HASHFUNC(Handle);
5470 LIST_FOR_EACH(e, &This->patches[i]) {
5471 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5472 if(patch->Handle == Handle) {
5473 TRACE("Deleting patch %p\n", patch);
5474 list_remove(&patch->entry);
5475 HeapFree(GetProcessHeap(), 0, patch->mem);
5476 HeapFree(GetProcessHeap(), 0, patch);
5477 return WINED3D_OK;
5481 /* TODO: Write a test for the return value */
5482 FIXME("Attempt to destroy nonexistent patch\n");
5483 return WINED3DERR_INVALIDCALL;
5486 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5487 const WINED3DRECT *rect, const float color[4])
5489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5490 struct wined3d_context *context;
5492 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5493 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5495 context = context_acquire(This, surface);
5496 context_apply_clear_state(context, This, surface, NULL);
5498 ENTER_GL();
5500 if (rect)
5502 if (surface_is_offscreen(surface))
5503 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5504 else
5505 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5506 rect->x2 - rect->x1, rect->y2 - rect->y1);
5507 checkGLcall("glScissor");
5509 else
5511 glDisable(GL_SCISSOR_TEST);
5514 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5520 glClearColor(color[0], color[1], color[2], color[3]);
5521 glClear(GL_COLOR_BUFFER_BIT);
5522 checkGLcall("glClear");
5524 LEAVE_GL();
5526 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5528 context_release(context);
5531 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5532 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5534 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5535 WINEDDBLTFX BltFx;
5537 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5539 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5540 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5541 return WINED3DERR_INVALIDCALL;
5544 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5545 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5546 color_fill_fbo(iface, surface, pRect, c);
5547 return WINED3D_OK;
5548 } else {
5549 /* Just forward this to the DirectDraw blitting engine */
5550 memset(&BltFx, 0, sizeof(BltFx));
5551 BltFx.dwSize = sizeof(BltFx);
5552 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5553 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5554 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5558 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5559 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5561 IWineD3DResource *resource;
5562 IWineD3DSurfaceImpl *surface;
5563 HRESULT hr;
5565 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5566 if (FAILED(hr))
5568 ERR("Failed to get resource, hr %#x\n", hr);
5569 return;
5572 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5574 FIXME("Only supported on surface resources\n");
5575 IWineD3DResource_Release(resource);
5576 return;
5579 surface = (IWineD3DSurfaceImpl *)resource;
5581 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5583 color_fill_fbo(iface, surface, NULL, color);
5585 else
5587 WINEDDBLTFX BltFx;
5588 WINED3DCOLOR c;
5590 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5592 c = ((DWORD)(color[2] * 255.0f));
5593 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5594 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5595 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5597 /* Just forward this to the DirectDraw blitting engine */
5598 memset(&BltFx, 0, sizeof(BltFx));
5599 BltFx.dwSize = sizeof(BltFx);
5600 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5601 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5602 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5603 if (FAILED(hr))
5605 ERR("Blt failed, hr %#x\n", hr);
5609 IWineD3DResource_Release(resource);
5612 /* rendertarget and depth stencil functions */
5613 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5618 ERR("(%p) : Only %d render targets are supported.\n",
5619 This, This->adapter->gl_info.limits.buffers);
5620 return WINED3DERR_INVALIDCALL;
5623 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5624 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5625 /* Note inc ref on returned surface */
5626 if(*ppRenderTarget != NULL)
5627 IWineD3DSurface_AddRef(*ppRenderTarget);
5628 return WINED3D_OK;
5631 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5632 IWineD3DSurface *front, IWineD3DSurface *back)
5634 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5635 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5636 IWineD3DSwapChainImpl *swapchain;
5637 HRESULT hr;
5639 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5641 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5643 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5644 return hr;
5647 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5649 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5650 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5651 return WINED3DERR_INVALIDCALL;
5654 if (back_impl)
5656 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5658 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5659 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5660 return WINED3DERR_INVALIDCALL;
5663 if (!swapchain->back_buffers)
5665 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5666 if (!swapchain->back_buffers)
5668 ERR("Failed to allocate back buffer array memory.\n");
5669 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5670 return E_OUTOFMEMORY;
5675 if (swapchain->front_buffer != front_impl)
5677 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5679 if (swapchain->front_buffer)
5681 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5682 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5684 swapchain->front_buffer = front_impl;
5686 if (front)
5688 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5689 front_impl->Flags |= SFLAG_SWAPCHAIN;
5693 if (swapchain->back_buffers[0] != back_impl)
5695 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5697 if (swapchain->back_buffers[0])
5699 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5700 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5702 swapchain->back_buffers[0] = back_impl;
5704 if (back)
5706 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5707 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5708 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5709 swapchain->presentParms.BackBufferCount = 1;
5711 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5712 back_impl->Flags |= SFLAG_SWAPCHAIN;
5714 else
5716 swapchain->presentParms.BackBufferCount = 0;
5717 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5718 swapchain->back_buffers = NULL;
5722 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5729 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5731 if(*ppZStencilSurface != NULL) {
5732 /* Note inc ref on returned surface */
5733 IWineD3DSurface_AddRef(*ppZStencilSurface);
5734 return WINED3D_OK;
5735 } else {
5736 return WINED3DERR_NOTFOUND;
5740 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5741 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5743 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5744 const struct wined3d_gl_info *gl_info;
5745 struct wined3d_context *context;
5746 GLenum gl_filter;
5747 RECT src_rect, dst_rect;
5749 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5750 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5751 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5753 src_rect = *src_rect_in;
5754 dst_rect = *dst_rect_in;
5756 switch (filter) {
5757 case WINED3DTEXF_LINEAR:
5758 gl_filter = GL_LINEAR;
5759 break;
5761 default:
5762 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5763 case WINED3DTEXF_NONE:
5764 case WINED3DTEXF_POINT:
5765 gl_filter = GL_NEAREST;
5766 break;
5769 /* Make sure the drawables are up-to-date. Note that loading the
5770 * destination surface isn't strictly required if we overwrite the
5771 * entire surface. */
5772 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5773 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5775 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface);
5776 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface);
5777 else context = context_acquire(device, NULL);
5779 if (!context->valid)
5781 context_release(context);
5782 WARN("Invalid context, skipping blit.\n");
5783 return;
5786 gl_info = context->gl_info;
5788 if (!surface_is_offscreen(src_surface))
5790 GLenum buffer = surface_get_gl_buffer(src_surface);
5792 TRACE("Source surface %p is onscreen\n", src_surface);
5794 if (buffer == GL_FRONT)
5795 surface_translate_frontbuffer_coords(src_surface, context->win_handle, &src_rect);
5797 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5798 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5800 ENTER_GL();
5801 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5802 glReadBuffer(buffer);
5803 checkGLcall("glReadBuffer()");
5804 } else {
5805 TRACE("Source surface %p is offscreen\n", src_surface);
5806 ENTER_GL();
5807 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL);
5808 glReadBuffer(GL_COLOR_ATTACHMENT0);
5809 checkGLcall("glReadBuffer()");
5811 LEAVE_GL();
5813 /* Attach dst surface to dst fbo */
5814 if (!surface_is_offscreen(dst_surface))
5816 GLenum buffer = surface_get_gl_buffer(dst_surface);
5818 TRACE("Destination surface %p is onscreen\n", dst_surface);
5820 if (buffer == GL_FRONT)
5821 surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect);
5823 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5824 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5826 ENTER_GL();
5827 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5828 context_set_draw_buffer(context, buffer);
5830 else
5832 TRACE("Destination surface %p is offscreen\n", dst_surface);
5834 ENTER_GL();
5835 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL);
5836 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5838 glDisable(GL_SCISSOR_TEST);
5839 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5841 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5842 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5843 checkGLcall("glBlitFramebuffer()");
5845 LEAVE_GL();
5847 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5849 context_release(context);
5851 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5854 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5855 BOOL set_viewport) {
5856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5860 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5862 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5863 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5864 return WINED3DERR_INVALIDCALL;
5867 /* MSDN says that null disables the render target
5868 but a device must always be associated with a render target
5869 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5871 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5872 FIXME("Trying to set render target 0 to NULL\n");
5873 return WINED3DERR_INVALIDCALL;
5875 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5876 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
5877 return WINED3DERR_INVALIDCALL;
5880 /* If we are trying to set what we already have, don't bother */
5881 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5883 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5884 return WINED3D_OK;
5886 if (pRenderTarget)
5887 IWineD3DSurface_AddRef(pRenderTarget);
5888 if (This->render_targets[RenderTargetIndex])
5889 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5890 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5892 /* Render target 0 is special */
5893 if(RenderTargetIndex == 0 && set_viewport) {
5894 /* Finally, reset the viewport and scissor rect as the MSDN states.
5895 * Tests show that stateblock recording is ignored, the change goes
5896 * directly into the primary stateblock.
5898 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5899 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5900 This->stateBlock->viewport.X = 0;
5901 This->stateBlock->viewport.Y = 0;
5902 This->stateBlock->viewport.MaxZ = 1.0f;
5903 This->stateBlock->viewport.MinZ = 0.0f;
5904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5906 This->stateBlock->scissorRect.top = 0;
5907 This->stateBlock->scissorRect.left = 0;
5908 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5909 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5912 return WINED3D_OK;
5915 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5917 IWineD3DSurfaceImpl *tmp;
5919 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5921 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5923 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5924 return WINED3D_OK;
5927 if (This->depth_stencil)
5929 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5930 || This->depth_stencil->Flags & SFLAG_DISCARD)
5932 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5933 This->depth_stencil->currentDesc.Width,
5934 This->depth_stencil->currentDesc.Height);
5935 if (This->depth_stencil == This->onscreen_depth_stencil)
5937 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5938 This->onscreen_depth_stencil = NULL;
5943 tmp = This->depth_stencil;
5944 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5945 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5946 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5948 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5950 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5956 return WINED3D_OK;
5959 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5960 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5962 /* TODO: the use of Impl is deprecated. */
5963 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5964 WINED3DLOCKED_RECT lockedRect;
5966 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5968 /* some basic validation checks */
5969 if (This->cursorTexture)
5971 struct wined3d_context *context = context_acquire(This, NULL);
5972 ENTER_GL();
5973 glDeleteTextures(1, &This->cursorTexture);
5974 LEAVE_GL();
5975 context_release(context);
5976 This->cursorTexture = 0;
5979 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5980 This->haveHardwareCursor = TRUE;
5981 else
5982 This->haveHardwareCursor = FALSE;
5984 if(pCursorBitmap) {
5985 WINED3DLOCKED_RECT rect;
5987 /* MSDN: Cursor must be A8R8G8B8 */
5988 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5990 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5991 return WINED3DERR_INVALIDCALL;
5994 /* MSDN: Cursor must be smaller than the display mode */
5995 if(pSur->currentDesc.Width > This->ddraw_width ||
5996 pSur->currentDesc.Height > This->ddraw_height) {
5997 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5998 return WINED3DERR_INVALIDCALL;
6001 if (!This->haveHardwareCursor) {
6002 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6004 /* Do not store the surface's pointer because the application may
6005 * release it after setting the cursor image. Windows doesn't
6006 * addref the set surface, so we can't do this either without
6007 * creating circular refcount dependencies. Copy out the gl texture
6008 * instead.
6010 This->cursorWidth = pSur->currentDesc.Width;
6011 This->cursorHeight = pSur->currentDesc.Height;
6012 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6014 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6015 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6016 struct wined3d_context *context;
6017 char *mem, *bits = rect.pBits;
6018 GLint intfmt = format_desc->glInternal;
6019 GLint format = format_desc->glFormat;
6020 GLint type = format_desc->glType;
6021 INT height = This->cursorHeight;
6022 INT width = This->cursorWidth;
6023 INT bpp = format_desc->byte_count;
6024 DWORD sampler;
6025 INT i;
6027 /* Reformat the texture memory (pitch and width can be
6028 * different) */
6029 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6030 for(i = 0; i < height; i++)
6031 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6032 IWineD3DSurface_UnlockRect(pCursorBitmap);
6034 context = context_acquire(This, NULL);
6036 ENTER_GL();
6038 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6040 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6041 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6044 /* Make sure that a proper texture unit is selected */
6045 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6046 checkGLcall("glActiveTextureARB");
6047 sampler = This->rev_tex_unit_map[0];
6048 if (sampler != WINED3D_UNMAPPED_STAGE)
6050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6052 /* Create a new cursor texture */
6053 glGenTextures(1, &This->cursorTexture);
6054 checkGLcall("glGenTextures");
6055 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6056 checkGLcall("glBindTexture");
6057 /* Copy the bitmap memory into the cursor texture */
6058 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6059 HeapFree(GetProcessHeap(), 0, mem);
6060 checkGLcall("glTexImage2D");
6062 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6064 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6065 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6068 LEAVE_GL();
6070 context_release(context);
6072 else
6074 FIXME("A cursor texture was not returned.\n");
6075 This->cursorTexture = 0;
6078 else
6080 /* Draw a hardware cursor */
6081 ICONINFO cursorInfo;
6082 HCURSOR cursor;
6083 /* Create and clear maskBits because it is not needed for
6084 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6085 * chunks. */
6086 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6087 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6088 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6089 WINED3DLOCK_NO_DIRTY_UPDATE |
6090 WINED3DLOCK_READONLY
6092 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6093 pSur->currentDesc.Height);
6095 cursorInfo.fIcon = FALSE;
6096 cursorInfo.xHotspot = XHotSpot;
6097 cursorInfo.yHotspot = YHotSpot;
6098 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6099 1, 1, maskBits);
6100 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6101 1, 32, lockedRect.pBits);
6102 IWineD3DSurface_UnlockRect(pCursorBitmap);
6103 /* Create our cursor and clean up. */
6104 cursor = CreateIconIndirect(&cursorInfo);
6105 SetCursor(cursor);
6106 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6107 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6108 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6109 This->hardwareCursor = cursor;
6110 HeapFree(GetProcessHeap(), 0, maskBits);
6114 This->xHotSpot = XHotSpot;
6115 This->yHotSpot = YHotSpot;
6116 return WINED3D_OK;
6119 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6121 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6123 This->xScreenSpace = XScreenSpace;
6124 This->yScreenSpace = YScreenSpace;
6126 return;
6130 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6132 BOOL oldVisible = This->bCursorVisible;
6133 POINT pt;
6135 TRACE("(%p) : visible(%d)\n", This, bShow);
6138 * When ShowCursor is first called it should make the cursor appear at the OS's last
6139 * known cursor position. Because of this, some applications just repetitively call
6140 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6142 GetCursorPos(&pt);
6143 This->xScreenSpace = pt.x;
6144 This->yScreenSpace = pt.y;
6146 if (This->haveHardwareCursor) {
6147 This->bCursorVisible = bShow;
6148 if (bShow)
6149 SetCursor(This->hardwareCursor);
6150 else
6151 SetCursor(NULL);
6153 else
6155 if (This->cursorTexture)
6156 This->bCursorVisible = bShow;
6159 return oldVisible;
6162 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6163 TRACE("checking resource %p for eviction\n", resource);
6164 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6165 TRACE("Evicting %p\n", resource);
6166 IWineD3DResource_UnLoad(resource);
6168 IWineD3DResource_Release(resource);
6169 return S_OK;
6172 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6174 TRACE("iface %p.\n", iface);
6176 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6177 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6178 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6180 return WINED3D_OK;
6183 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6185 IWineD3DDeviceImpl *device = surface->resource.device;
6186 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6188 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6189 if(surface->Flags & SFLAG_DIBSECTION) {
6190 /* Release the DC */
6191 SelectObject(surface->hDC, surface->dib.holdbitmap);
6192 DeleteDC(surface->hDC);
6193 /* Release the DIB section */
6194 DeleteObject(surface->dib.DIBsection);
6195 surface->dib.bitmap_data = NULL;
6196 surface->resource.allocatedMemory = NULL;
6197 surface->Flags &= ~SFLAG_DIBSECTION;
6199 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6200 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6201 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6202 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6204 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6205 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6206 } else {
6207 surface->pow2Width = surface->pow2Height = 1;
6208 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6209 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6212 if (surface->texture_name)
6214 struct wined3d_context *context = context_acquire(device, NULL);
6215 ENTER_GL();
6216 glDeleteTextures(1, &surface->texture_name);
6217 LEAVE_GL();
6218 context_release(context);
6219 surface->texture_name = 0;
6220 surface->Flags &= ~SFLAG_CLIENT;
6222 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6223 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6224 surface->Flags |= SFLAG_NONPOW2;
6225 } else {
6226 surface->Flags &= ~SFLAG_NONPOW2;
6228 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6229 surface->resource.allocatedMemory = NULL;
6230 surface->resource.heapMemory = NULL;
6231 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6233 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6234 * to a FBO */
6235 if (!surface_init_sysmem(surface))
6237 return E_OUTOFMEMORY;
6239 return WINED3D_OK;
6242 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6243 TRACE("Unloading resource %p\n", resource);
6244 IWineD3DResource_UnLoad(resource);
6245 IWineD3DResource_Release(resource);
6246 return S_OK;
6249 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6251 UINT i, count;
6252 WINED3DDISPLAYMODE m;
6253 HRESULT hr;
6255 /* All Windowed modes are supported, as is leaving the current mode */
6256 if(pp->Windowed) return TRUE;
6257 if(!pp->BackBufferWidth) return TRUE;
6258 if(!pp->BackBufferHeight) return TRUE;
6260 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6261 for(i = 0; i < count; i++) {
6262 memset(&m, 0, sizeof(m));
6263 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6264 if(FAILED(hr)) {
6265 ERR("EnumAdapterModes failed\n");
6267 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6268 /* Mode found, it is supported */
6269 return TRUE;
6272 /* Mode not found -> not supported */
6273 return FALSE;
6276 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6279 const struct wined3d_gl_info *gl_info;
6280 struct wined3d_context *context;
6281 IWineD3DBaseShaderImpl *shader;
6283 context = context_acquire(This, NULL);
6284 gl_info = context->gl_info;
6286 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6287 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6288 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6291 ENTER_GL();
6292 if(This->depth_blt_texture) {
6293 glDeleteTextures(1, &This->depth_blt_texture);
6294 This->depth_blt_texture = 0;
6296 if (This->depth_blt_rb) {
6297 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6298 This->depth_blt_rb = 0;
6299 This->depth_blt_rb_w = 0;
6300 This->depth_blt_rb_h = 0;
6302 LEAVE_GL();
6304 This->blitter->free_private(iface);
6305 This->frag_pipe->free_private(iface);
6306 This->shader_backend->shader_free_private(iface);
6307 destroy_dummy_textures(This, gl_info);
6309 context_release(context);
6311 while (This->numContexts)
6313 context_destroy(This, This->contexts[0]);
6315 HeapFree(GetProcessHeap(), 0, swapchain->context);
6316 swapchain->context = NULL;
6317 swapchain->num_contexts = 0;
6320 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6323 struct wined3d_context *context;
6324 HRESULT hr;
6325 IWineD3DSurfaceImpl *target;
6327 /* Recreate the primary swapchain's context */
6328 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6329 if (!swapchain->context)
6331 ERR("Failed to allocate memory for swapchain context array.\n");
6332 return E_OUTOFMEMORY;
6335 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6336 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6338 WARN("Failed to create context.\n");
6339 HeapFree(GetProcessHeap(), 0, swapchain->context);
6340 return E_FAIL;
6343 swapchain->context[0] = context;
6344 swapchain->num_contexts = 1;
6345 create_dummy_textures(This);
6346 context_release(context);
6348 hr = This->shader_backend->shader_alloc_private(iface);
6349 if (FAILED(hr))
6351 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6352 goto err;
6355 hr = This->frag_pipe->alloc_private(iface);
6356 if (FAILED(hr))
6358 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6359 This->shader_backend->shader_free_private(iface);
6360 goto err;
6363 hr = This->blitter->alloc_private(iface);
6364 if (FAILED(hr))
6366 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6367 This->frag_pipe->free_private(iface);
6368 This->shader_backend->shader_free_private(iface);
6369 goto err;
6372 return WINED3D_OK;
6374 err:
6375 context_acquire(This, NULL);
6376 destroy_dummy_textures(This, context->gl_info);
6377 context_release(context);
6378 context_destroy(This, context);
6379 HeapFree(GetProcessHeap(), 0, swapchain->context);
6380 swapchain->num_contexts = 0;
6381 return hr;
6384 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6386 IWineD3DSwapChainImpl *swapchain;
6387 HRESULT hr;
6388 BOOL DisplayModeChanged = FALSE;
6389 WINED3DDISPLAYMODE mode;
6390 TRACE("(%p)\n", This);
6392 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6393 if(FAILED(hr)) {
6394 ERR("Failed to get the first implicit swapchain\n");
6395 return hr;
6398 if(!is_display_mode_supported(This, pPresentationParameters)) {
6399 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6400 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6401 pPresentationParameters->BackBufferHeight);
6402 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6403 return WINED3DERR_INVALIDCALL;
6406 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6407 * on an existing gl context, so there's no real need for recreation.
6409 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6411 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6413 TRACE("New params:\n");
6414 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6415 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6416 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6417 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6418 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6419 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6420 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6421 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6422 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6423 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6424 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6425 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6426 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6428 /* No special treatment of these parameters. Just store them */
6429 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6430 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6431 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6432 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6434 /* What to do about these? */
6435 if(pPresentationParameters->BackBufferCount != 0 &&
6436 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6437 ERR("Cannot change the back buffer count yet\n");
6439 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6440 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6441 ERR("Cannot change the back buffer format yet\n");
6443 if(pPresentationParameters->hDeviceWindow != NULL &&
6444 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6445 ERR("Cannot change the device window yet\n");
6447 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6449 HRESULT hrc;
6451 TRACE("Creating the depth stencil buffer\n");
6453 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6454 This->parent,
6455 pPresentationParameters->BackBufferWidth,
6456 pPresentationParameters->BackBufferHeight,
6457 pPresentationParameters->AutoDepthStencilFormat,
6458 pPresentationParameters->MultiSampleType,
6459 pPresentationParameters->MultiSampleQuality,
6460 FALSE,
6461 (IWineD3DSurface **)&This->auto_depth_stencil);
6463 if (FAILED(hrc)) {
6464 ERR("Failed to create the depth stencil buffer\n");
6465 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6466 return WINED3DERR_INVALIDCALL;
6470 if (This->onscreen_depth_stencil)
6472 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6473 This->onscreen_depth_stencil = NULL;
6476 /* Reset the depth stencil */
6477 if (pPresentationParameters->EnableAutoDepthStencil)
6478 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6479 else
6480 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6482 TRACE("Resetting stateblock\n");
6483 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6484 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6486 delete_opengl_contexts(iface, swapchain);
6488 if(pPresentationParameters->Windowed) {
6489 mode.Width = swapchain->orig_width;
6490 mode.Height = swapchain->orig_height;
6491 mode.RefreshRate = 0;
6492 mode.Format = swapchain->presentParms.BackBufferFormat;
6493 } else {
6494 mode.Width = pPresentationParameters->BackBufferWidth;
6495 mode.Height = pPresentationParameters->BackBufferHeight;
6496 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6497 mode.Format = swapchain->presentParms.BackBufferFormat;
6500 /* Should Width == 800 && Height == 0 set 800x600? */
6501 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6502 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6503 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6505 UINT i;
6507 if(!pPresentationParameters->Windowed) {
6508 DisplayModeChanged = TRUE;
6510 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6511 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6513 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6514 if(FAILED(hr))
6516 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6517 return hr;
6520 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6522 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6523 if(FAILED(hr))
6525 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6526 return hr;
6529 if (This->auto_depth_stencil)
6531 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6532 if(FAILED(hr))
6534 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6535 return hr;
6540 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6541 || DisplayModeChanged)
6543 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6545 if (!pPresentationParameters->Windowed)
6547 if(swapchain->presentParms.Windowed) {
6548 /* switch from windowed to fs */
6549 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6550 pPresentationParameters->BackBufferHeight);
6551 } else {
6552 /* Fullscreen -> fullscreen mode change */
6553 MoveWindow(swapchain->device_window, 0, 0,
6554 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6555 TRUE);
6558 else if (!swapchain->presentParms.Windowed)
6560 /* Fullscreen -> windowed switch */
6561 swapchain_restore_fullscreen_window(swapchain);
6563 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6564 } else if(!pPresentationParameters->Windowed) {
6565 DWORD style = This->style, exStyle = This->exStyle;
6566 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6567 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6568 * Reset to clear up their mess. Guild Wars also loses the device during that.
6570 This->style = 0;
6571 This->exStyle = 0;
6572 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6573 pPresentationParameters->BackBufferHeight);
6574 This->style = style;
6575 This->exStyle = exStyle;
6578 /* Note: No parent needed for initial internal stateblock */
6579 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6580 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6581 else TRACE("Created stateblock %p\n", This->stateBlock);
6582 This->updateStateBlock = This->stateBlock;
6583 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6585 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6586 if(FAILED(hr)) {
6587 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6590 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6592 RECT client_rect;
6593 GetClientRect(swapchain->win_handle, &client_rect);
6595 if(!swapchain->presentParms.BackBufferCount)
6597 TRACE("Single buffered rendering\n");
6598 swapchain->render_to_fbo = FALSE;
6600 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6601 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6603 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6604 swapchain->presentParms.BackBufferWidth,
6605 swapchain->presentParms.BackBufferHeight,
6606 client_rect.right, client_rect.bottom);
6607 swapchain->render_to_fbo = TRUE;
6609 else
6611 TRACE("Rendering directly to GL_BACK\n");
6612 swapchain->render_to_fbo = FALSE;
6616 hr = create_primary_opengl_context(iface, swapchain);
6617 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6619 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6620 * first use
6622 return hr;
6625 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6627 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6629 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6631 return WINED3D_OK;
6635 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6637 TRACE("(%p) : pParameters %p\n", This, pParameters);
6639 *pParameters = This->createParms;
6640 return WINED3D_OK;
6643 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6644 IWineD3DSwapChain *swapchain;
6646 TRACE("Relaying to swapchain\n");
6648 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6649 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6650 IWineD3DSwapChain_Release(swapchain);
6654 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6655 IWineD3DSwapChain *swapchain;
6657 TRACE("Relaying to swapchain\n");
6659 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6660 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6661 IWineD3DSwapChain_Release(swapchain);
6666 /** ********************************************************
6667 * Notification functions
6668 ** ********************************************************/
6669 /** This function must be called in the release of a resource when ref == 0,
6670 * the contents of resource must still be correct,
6671 * any handles to other resource held by the caller must be closed
6672 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6673 *****************************************************/
6674 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6676 TRACE("(%p) : Adding resource %p\n", This, resource);
6678 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6681 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6683 TRACE("(%p) : Removing resource %p\n", This, resource);
6685 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6688 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6690 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6691 int counter;
6693 TRACE("(%p) : resource %p\n", This, resource);
6695 context_resource_released((IWineD3DDevice *)This, resource, type);
6697 switch (type) {
6698 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6699 case WINED3DRTYPE_SURFACE: {
6700 unsigned int i;
6702 if (This->d3d_initialized)
6704 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6706 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6707 This->render_targets[i] = NULL;
6709 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6710 This->depth_stencil = NULL;
6713 break;
6715 case WINED3DRTYPE_TEXTURE:
6716 case WINED3DRTYPE_CUBETEXTURE:
6717 case WINED3DRTYPE_VOLUMETEXTURE:
6718 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6719 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6720 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6721 This->stateBlock->textures[counter] = NULL;
6723 if (This->updateStateBlock != This->stateBlock ){
6724 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6725 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6726 This->updateStateBlock->textures[counter] = NULL;
6730 break;
6731 case WINED3DRTYPE_VOLUME:
6732 /* TODO: nothing really? */
6733 break;
6734 case WINED3DRTYPE_BUFFER:
6736 int streamNumber;
6737 TRACE("Cleaning up stream pointers\n");
6739 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6740 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6741 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6743 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6744 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6745 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6746 This->updateStateBlock->streamSource[streamNumber] = 0;
6747 /* Set changed flag? */
6750 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6751 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6752 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6753 This->stateBlock->streamSource[streamNumber] = 0;
6758 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6759 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6760 This->updateStateBlock->pIndexData = NULL;
6763 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6764 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6765 This->stateBlock->pIndexData = NULL;
6769 break;
6771 default:
6772 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6773 break;
6777 /* Remove the resource from the resourceStore */
6778 device_resource_remove(This, resource);
6780 TRACE("Resource released\n");
6784 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6786 IWineD3DResourceImpl *resource, *cursor;
6787 HRESULT ret;
6788 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6790 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6791 TRACE("enumerating resource %p\n", resource);
6792 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6793 ret = pCallback((IWineD3DResource *) resource, pData);
6794 if(ret == S_FALSE) {
6795 TRACE("Canceling enumeration\n");
6796 break;
6799 return WINED3D_OK;
6802 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6805 IWineD3DResourceImpl *resource;
6807 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6809 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6810 if (type == WINED3DRTYPE_SURFACE)
6812 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6814 TRACE("Found surface %p for dc %p.\n", resource, dc);
6815 *surface = (IWineD3DSurface *)resource;
6816 return WINED3D_OK;
6821 return WINED3DERR_INVALIDCALL;
6824 /**********************************************************
6825 * IWineD3DDevice VTbl follows
6826 **********************************************************/
6828 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6830 /*** IUnknown methods ***/
6831 IWineD3DDeviceImpl_QueryInterface,
6832 IWineD3DDeviceImpl_AddRef,
6833 IWineD3DDeviceImpl_Release,
6834 /*** IWineD3DDevice methods ***/
6835 IWineD3DDeviceImpl_GetParent,
6836 /*** Creation methods**/
6837 IWineD3DDeviceImpl_CreateBuffer,
6838 IWineD3DDeviceImpl_CreateVertexBuffer,
6839 IWineD3DDeviceImpl_CreateIndexBuffer,
6840 IWineD3DDeviceImpl_CreateStateBlock,
6841 IWineD3DDeviceImpl_CreateSurface,
6842 IWineD3DDeviceImpl_CreateRendertargetView,
6843 IWineD3DDeviceImpl_CreateTexture,
6844 IWineD3DDeviceImpl_CreateVolumeTexture,
6845 IWineD3DDeviceImpl_CreateVolume,
6846 IWineD3DDeviceImpl_CreateCubeTexture,
6847 IWineD3DDeviceImpl_CreateQuery,
6848 IWineD3DDeviceImpl_CreateSwapChain,
6849 IWineD3DDeviceImpl_CreateVertexDeclaration,
6850 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6851 IWineD3DDeviceImpl_CreateVertexShader,
6852 IWineD3DDeviceImpl_CreateGeometryShader,
6853 IWineD3DDeviceImpl_CreatePixelShader,
6854 IWineD3DDeviceImpl_CreatePalette,
6855 /*** Odd functions **/
6856 IWineD3DDeviceImpl_Init3D,
6857 IWineD3DDeviceImpl_InitGDI,
6858 IWineD3DDeviceImpl_Uninit3D,
6859 IWineD3DDeviceImpl_UninitGDI,
6860 IWineD3DDeviceImpl_SetMultithreaded,
6861 IWineD3DDeviceImpl_EvictManagedResources,
6862 IWineD3DDeviceImpl_GetAvailableTextureMem,
6863 IWineD3DDeviceImpl_GetBackBuffer,
6864 IWineD3DDeviceImpl_GetCreationParameters,
6865 IWineD3DDeviceImpl_GetDeviceCaps,
6866 IWineD3DDeviceImpl_GetDirect3D,
6867 IWineD3DDeviceImpl_GetDisplayMode,
6868 IWineD3DDeviceImpl_SetDisplayMode,
6869 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6870 IWineD3DDeviceImpl_GetRasterStatus,
6871 IWineD3DDeviceImpl_GetSwapChain,
6872 IWineD3DDeviceImpl_Reset,
6873 IWineD3DDeviceImpl_SetDialogBoxMode,
6874 IWineD3DDeviceImpl_SetCursorProperties,
6875 IWineD3DDeviceImpl_SetCursorPosition,
6876 IWineD3DDeviceImpl_ShowCursor,
6877 /*** Getters and setters **/
6878 IWineD3DDeviceImpl_SetClipPlane,
6879 IWineD3DDeviceImpl_GetClipPlane,
6880 IWineD3DDeviceImpl_SetClipStatus,
6881 IWineD3DDeviceImpl_GetClipStatus,
6882 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6883 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6884 IWineD3DDeviceImpl_SetDepthStencilSurface,
6885 IWineD3DDeviceImpl_GetDepthStencilSurface,
6886 IWineD3DDeviceImpl_SetGammaRamp,
6887 IWineD3DDeviceImpl_GetGammaRamp,
6888 IWineD3DDeviceImpl_SetIndexBuffer,
6889 IWineD3DDeviceImpl_GetIndexBuffer,
6890 IWineD3DDeviceImpl_SetBaseVertexIndex,
6891 IWineD3DDeviceImpl_GetBaseVertexIndex,
6892 IWineD3DDeviceImpl_SetLight,
6893 IWineD3DDeviceImpl_GetLight,
6894 IWineD3DDeviceImpl_SetLightEnable,
6895 IWineD3DDeviceImpl_GetLightEnable,
6896 IWineD3DDeviceImpl_SetMaterial,
6897 IWineD3DDeviceImpl_GetMaterial,
6898 IWineD3DDeviceImpl_SetNPatchMode,
6899 IWineD3DDeviceImpl_GetNPatchMode,
6900 IWineD3DDeviceImpl_SetPaletteEntries,
6901 IWineD3DDeviceImpl_GetPaletteEntries,
6902 IWineD3DDeviceImpl_SetPixelShader,
6903 IWineD3DDeviceImpl_GetPixelShader,
6904 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6905 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6906 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6907 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6908 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6909 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6910 IWineD3DDeviceImpl_SetRenderState,
6911 IWineD3DDeviceImpl_GetRenderState,
6912 IWineD3DDeviceImpl_SetRenderTarget,
6913 IWineD3DDeviceImpl_GetRenderTarget,
6914 IWineD3DDeviceImpl_SetFrontBackBuffers,
6915 IWineD3DDeviceImpl_SetSamplerState,
6916 IWineD3DDeviceImpl_GetSamplerState,
6917 IWineD3DDeviceImpl_SetScissorRect,
6918 IWineD3DDeviceImpl_GetScissorRect,
6919 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6920 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6921 IWineD3DDeviceImpl_SetStreamSource,
6922 IWineD3DDeviceImpl_GetStreamSource,
6923 IWineD3DDeviceImpl_SetStreamSourceFreq,
6924 IWineD3DDeviceImpl_GetStreamSourceFreq,
6925 IWineD3DDeviceImpl_SetTexture,
6926 IWineD3DDeviceImpl_GetTexture,
6927 IWineD3DDeviceImpl_SetTextureStageState,
6928 IWineD3DDeviceImpl_GetTextureStageState,
6929 IWineD3DDeviceImpl_SetTransform,
6930 IWineD3DDeviceImpl_GetTransform,
6931 IWineD3DDeviceImpl_SetVertexDeclaration,
6932 IWineD3DDeviceImpl_GetVertexDeclaration,
6933 IWineD3DDeviceImpl_SetVertexShader,
6934 IWineD3DDeviceImpl_GetVertexShader,
6935 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6936 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6939 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6940 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6941 IWineD3DDeviceImpl_SetViewport,
6942 IWineD3DDeviceImpl_GetViewport,
6943 IWineD3DDeviceImpl_MultiplyTransform,
6944 IWineD3DDeviceImpl_ValidateDevice,
6945 IWineD3DDeviceImpl_ProcessVertices,
6946 /*** State block ***/
6947 IWineD3DDeviceImpl_BeginStateBlock,
6948 IWineD3DDeviceImpl_EndStateBlock,
6949 /*** Scene management ***/
6950 IWineD3DDeviceImpl_BeginScene,
6951 IWineD3DDeviceImpl_EndScene,
6952 IWineD3DDeviceImpl_Present,
6953 IWineD3DDeviceImpl_Clear,
6954 IWineD3DDeviceImpl_ClearRendertargetView,
6955 /*** Drawing ***/
6956 IWineD3DDeviceImpl_SetPrimitiveType,
6957 IWineD3DDeviceImpl_GetPrimitiveType,
6958 IWineD3DDeviceImpl_DrawPrimitive,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6960 IWineD3DDeviceImpl_DrawPrimitiveUP,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6962 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6963 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6964 IWineD3DDeviceImpl_DrawRectPatch,
6965 IWineD3DDeviceImpl_DrawTriPatch,
6966 IWineD3DDeviceImpl_DeletePatch,
6967 IWineD3DDeviceImpl_ColorFill,
6968 IWineD3DDeviceImpl_UpdateTexture,
6969 IWineD3DDeviceImpl_UpdateSurface,
6970 IWineD3DDeviceImpl_GetFrontBufferData,
6971 /*** object tracking ***/
6972 IWineD3DDeviceImpl_EnumResources,
6973 IWineD3DDeviceImpl_GetSurfaceFromDC,
6974 IWineD3DDeviceImpl_AcquireFocusWindow,
6975 IWineD3DDeviceImpl_ReleaseFocusWindow,
6978 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6979 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6980 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6982 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6983 const struct fragment_pipeline *fragment_pipeline;
6984 struct shader_caps shader_caps;
6985 struct fragment_caps ffp_caps;
6986 WINED3DDISPLAYMODE mode;
6987 unsigned int i;
6988 HRESULT hr;
6990 device->lpVtbl = &IWineD3DDevice_Vtbl;
6991 device->ref = 1;
6992 device->wined3d = (IWineD3D *)wined3d;
6993 IWineD3D_AddRef(device->wined3d);
6994 device->adapter = wined3d->adapter_count ? adapter : NULL;
6995 device->parent = parent;
6996 device->device_parent = device_parent;
6997 list_init(&device->resources);
6998 list_init(&device->shaders);
7000 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7001 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7003 /* Get the initial screen setup for ddraw. */
7004 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7005 if (FAILED(hr))
7007 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7008 IWineD3D_Release(device->wined3d);
7009 return hr;
7011 device->ddraw_width = mode.Width;
7012 device->ddraw_height = mode.Height;
7013 device->ddraw_format = mode.Format;
7015 /* Save the creation parameters. */
7016 device->createParms.AdapterOrdinal = adapter_idx;
7017 device->createParms.DeviceType = device_type;
7018 device->createParms.hFocusWindow = focus_window;
7019 device->createParms.BehaviorFlags = flags;
7021 device->devType = device_type;
7022 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7024 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7025 device->shader_backend = adapter->shader_backend;
7027 if (device->shader_backend)
7029 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7030 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7031 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7032 device->vs_clipping = shader_caps.VSClipping;
7034 fragment_pipeline = adapter->fragment_pipe;
7035 device->frag_pipe = fragment_pipeline;
7036 if (fragment_pipeline)
7038 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7039 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7041 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7042 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7043 if (FAILED(hr))
7045 ERR("Failed to compile state table, hr %#x.\n", hr);
7046 IWineD3D_Release(device->wined3d);
7047 return hr;
7050 device->blitter = adapter->blitter;
7052 return WINED3D_OK;
7056 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7057 DWORD rep = This->StateTable[state].representative;
7058 struct wined3d_context *context;
7059 DWORD idx;
7060 BYTE shift;
7061 UINT i;
7063 for(i = 0; i < This->numContexts; i++) {
7064 context = This->contexts[i];
7065 if(isStateDirty(context, rep)) continue;
7067 context->dirtyArray[context->numDirtyEntries++] = rep;
7068 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7069 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7070 context->isStateDirty[idx] |= (1 << shift);
7074 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7076 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7077 *width = context->current_rt->pow2Width;
7078 *height = context->current_rt->pow2Height;
7081 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7083 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7084 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7085 * current context's drawable, which is the size of the back buffer of the swapchain
7086 * the active context belongs to. */
7087 *width = swapchain->presentParms.BackBufferWidth;
7088 *height = swapchain->presentParms.BackBufferHeight;
7091 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7092 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7094 if (device->filter_messages)
7096 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7097 window, message, wparam, lparam);
7098 return DefWindowProcW(window, message, wparam, lparam);
7101 if (message == WM_DESTROY)
7103 TRACE("unregister window %p.\n", window);
7104 wined3d_unregister_window(window);
7106 if (device->focus_window == window) device->focus_window = NULL;
7107 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7110 return CallWindowProcW(proc, window, message, wparam, lparam);