wined3d: Make some functions static.
[wine/multimedia.git] / dlls / wined3d / device.c
blobfd5733590da757c74d7fce8ecb392c74fb655e6f
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);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 unsigned int i;
184 stream_info->use_map = 0;
185 stream_info->swizzle_map = 0;
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info->position_transformed = declaration->position_transformed;
189 if (declaration->position_transformed) use_vshader = FALSE;
191 /* Translate the declaration into strided data. */
192 for (i = 0; i < declaration->element_count; ++i)
194 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!This->stateBlock->streamSource[element->input_slot]) continue;
206 stride = This->stateBlock->streamStride[element->input_slot];
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 buffer_object = 0;
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
216 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &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 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
234 if (fixup)
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
293 stream_info->elements[idx].format_desc = element->format_desc;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
318 struct wined3d_event_query *query;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
333 query = ((struct wined3d_buffer *) buffer)->query;
334 if(query)
336 This->buffer_queries[This->num_buffer_queries++] = query;
342 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
343 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
345 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
346 e->format_desc = format_desc;
347 e->stride = strided->dwStride;
348 e->data = strided->lpData;
349 e->stream_idx = 0;
350 e->buffer_object = 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
354 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
356 unsigned int i;
358 memset(stream_info, 0, sizeof(*stream_info));
360 if (strided->position.lpData)
361 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
362 if (strided->normal.lpData)
363 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
364 if (strided->diffuse.lpData)
365 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
366 if (strided->specular.lpData)
367 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
369 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
371 if (strided->texCoords[i].lpData)
372 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
373 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
376 stream_info->position_transformed = strided->position_transformed;
378 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
380 if (!stream_info->elements[i].format_desc) continue;
382 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
383 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
385 stream_info->swizzle_map |= 1 << i;
387 stream_info->use_map |= 1 << i;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
414 struct wined3d_stream_info *stream_info = &device->strided_streams;
415 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
416 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
417 BOOL fixup = FALSE;
419 if (device->up_strided)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
424 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
426 else
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
432 if (vs && !stream_info->position_transformed)
434 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device->useDrawStridedSlow = TRUE;
439 else
441 device->useDrawStridedSlow = FALSE;
444 else
446 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
447 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
448 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
450 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
452 device->useDrawStridedSlow = TRUE;
454 else
456 device->useDrawStridedSlow = FALSE;
461 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
463 IWineD3DBaseTextureImpl *texture;
464 enum WINED3DSRGB srgb;
466 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
467 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
468 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
471 void device_preload_textures(IWineD3DDeviceImpl *device)
473 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
474 unsigned int i;
476 if (use_vs(stateblock))
478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
480 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
481 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
485 if (use_ps(stateblock))
487 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
489 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, i);
493 else
495 WORD ffu_map = device->fixed_function_usage_map;
497 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
499 if (ffu_map & 1)
500 device_preload_texture(stateblock, i);
505 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
507 struct wined3d_context **new_array;
509 TRACE("Adding context %p.\n", context);
511 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
512 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
514 if (!new_array)
516 ERR("Failed to grow the context array.\n");
517 return FALSE;
520 new_array[device->numContexts++] = context;
521 device->contexts = new_array;
522 return TRUE;
525 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
527 struct wined3d_context **new_array;
528 BOOL found = FALSE;
529 UINT i;
531 TRACE("Removing context %p.\n", context);
533 for (i = 0; i < device->numContexts; ++i)
535 if (device->contexts[i] == context)
537 found = TRUE;
538 break;
542 if (!found)
544 ERR("Context %p doesn't exist in context array.\n", context);
545 return;
548 if (!--device->numContexts)
550 HeapFree(GetProcessHeap(), 0, device->contexts);
551 device->contexts = NULL;
552 return;
555 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
556 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
557 if (!new_array)
559 ERR("Failed to shrink context array. Oh well.\n");
560 return;
563 device->contexts = new_array;
567 /**********************************************************
568 * IUnknown parts follows
569 **********************************************************/
571 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
575 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
576 if (IsEqualGUID(riid, &IID_IUnknown)
577 || IsEqualGUID(riid, &IID_IWineD3DBase)
578 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
579 IUnknown_AddRef(iface);
580 *ppobj = This;
581 return S_OK;
583 *ppobj = NULL;
584 return E_NOINTERFACE;
587 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 ULONG refCount = InterlockedIncrement(&This->ref);
591 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
592 return refCount;
595 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 ULONG refCount = InterlockedDecrement(&This->ref);
599 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
601 if (!refCount) {
602 UINT i;
604 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
605 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
606 This->multistate_funcs[i] = NULL;
609 /* TODO: Clean up all the surfaces and textures! */
610 /* NOTE: You must release the parent if the object was created via a callback
611 ** ***************************/
613 if (!list_empty(&This->resources))
615 IWineD3DResourceImpl *resource;
616 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
618 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
620 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
621 FIXME("Leftover resource %p with type %s (%#x).\n",
622 resource, debug_d3dresourcetype(type), type);
626 if(This->contexts) ERR("Context array not freed!\n");
627 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
628 This->haveHardwareCursor = FALSE;
630 IWineD3D_Release(This->wined3d);
631 This->wined3d = NULL;
632 HeapFree(GetProcessHeap(), 0, This);
633 TRACE("Freed device %p\n", This);
634 This = NULL;
636 return refCount;
639 /**********************************************************
640 * IWineD3DDevice implementation follows
641 **********************************************************/
642 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
644 *pParent = This->parent;
645 IUnknown_AddRef(This->parent);
646 return WINED3D_OK;
649 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
650 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
653 struct wined3d_buffer *object;
654 HRESULT hr;
656 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
658 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
659 if (!object)
661 ERR("Failed to allocate memory\n");
662 return E_OUTOFMEMORY;
665 FIXME("Ignoring access flags (pool)\n");
667 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
668 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
669 if (FAILED(hr))
671 WARN("Failed to initialize buffer, hr %#x.\n", hr);
672 HeapFree(GetProcessHeap(), 0, object);
673 return hr;
675 object->desc = *desc;
677 TRACE("Created buffer %p.\n", object);
679 *buffer = (IWineD3DBuffer *)object;
681 return WINED3D_OK;
684 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
685 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
686 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
689 struct wined3d_buffer *object;
690 HRESULT hr;
692 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
693 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
695 if (Pool == WINED3DPOOL_SCRATCH)
697 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
698 * anyway, SCRATCH vertex buffers aren't usable anywhere
700 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
701 *ppVertexBuffer = NULL;
702 return WINED3DERR_INVALIDCALL;
705 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
706 if (!object)
708 ERR("Out of memory\n");
709 *ppVertexBuffer = NULL;
710 return WINED3DERR_OUTOFVIDEOMEMORY;
713 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
714 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
715 if (FAILED(hr))
717 WARN("Failed to initialize buffer, hr %#x.\n", hr);
718 HeapFree(GetProcessHeap(), 0, object);
719 return hr;
722 TRACE("Created buffer %p.\n", object);
723 *ppVertexBuffer = (IWineD3DBuffer *)object;
725 return WINED3D_OK;
728 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
729 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
730 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
733 struct wined3d_buffer *object;
734 HRESULT hr;
736 TRACE("(%p) Creating index buffer\n", This);
738 /* Allocate the storage for the device */
739 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
740 if (!object)
742 ERR("Out of memory\n");
743 *ppIndexBuffer = NULL;
744 return WINED3DERR_OUTOFVIDEOMEMORY;
747 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
748 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
749 parent, parent_ops);
750 if (FAILED(hr))
752 WARN("Failed to initialize buffer, hr %#x\n", hr);
753 HeapFree(GetProcessHeap(), 0, object);
754 return hr;
757 TRACE("Created buffer %p.\n", object);
759 *ppIndexBuffer = (IWineD3DBuffer *) object;
761 return WINED3D_OK;
764 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
765 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
768 IWineD3DStateBlockImpl *object;
769 HRESULT hr;
771 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
772 if(!object)
774 ERR("Failed to allocate stateblock memory.\n");
775 return E_OUTOFMEMORY;
778 hr = stateblock_init(object, This, type);
779 if (FAILED(hr))
781 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
782 HeapFree(GetProcessHeap(), 0, object);
783 return hr;
786 TRACE("Created stateblock %p.\n", object);
787 *stateblock = (IWineD3DStateBlock *)object;
789 return WINED3D_OK;
792 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
793 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
794 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
795 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
798 IWineD3DSurfaceImpl *object;
799 HRESULT hr;
801 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
802 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
803 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
804 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
805 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
807 if (Impl == SURFACE_OPENGL && !This->adapter)
809 ERR("OpenGL surfaces are not available without OpenGL.\n");
810 return WINED3DERR_NOTAVAILABLE;
813 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
814 if (!object)
816 ERR("Failed to allocate surface memory.\n");
817 return WINED3DERR_OUTOFVIDEOMEMORY;
820 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
821 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
822 if (FAILED(hr))
824 WARN("Failed to initialize surface, returning %#x.\n", hr);
825 HeapFree(GetProcessHeap(), 0, object);
826 return hr;
829 TRACE("(%p) : Created surface %p\n", This, object);
831 *ppSurface = (IWineD3DSurface *)object;
833 return hr;
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
837 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
839 struct wined3d_rendertarget_view *object;
841 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
842 if (!object)
844 ERR("Failed to allocate memory\n");
845 return E_OUTOFMEMORY;
848 object->vtbl = &wined3d_rendertarget_view_vtbl;
849 object->refcount = 1;
850 IWineD3DResource_AddRef(resource);
851 object->resource = resource;
852 object->parent = parent;
854 *rendertarget_view = (IWineD3DRendertargetView *)object;
856 return WINED3D_OK;
859 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
860 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
861 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
864 IWineD3DTextureImpl *object;
865 HRESULT hr;
867 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
868 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
869 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
871 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
872 if (!object)
874 ERR("Out of memory\n");
875 *ppTexture = NULL;
876 return WINED3DERR_OUTOFVIDEOMEMORY;
879 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
880 if (FAILED(hr))
882 WARN("Failed to initialize texture, returning %#x\n", hr);
883 HeapFree(GetProcessHeap(), 0, object);
884 *ppTexture = NULL;
885 return hr;
888 *ppTexture = (IWineD3DTexture *)object;
890 TRACE("(%p) : Created texture %p\n", This, object);
892 return WINED3D_OK;
895 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
896 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
897 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
900 IWineD3DVolumeTextureImpl *object;
901 HRESULT hr;
903 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
904 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
906 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
907 if (!object)
909 ERR("Out of memory\n");
910 *ppVolumeTexture = NULL;
911 return WINED3DERR_OUTOFVIDEOMEMORY;
914 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
915 if (FAILED(hr))
917 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
918 HeapFree(GetProcessHeap(), 0, object);
919 *ppVolumeTexture = NULL;
920 return hr;
923 TRACE("(%p) : Created volume texture %p.\n", This, object);
924 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
926 return WINED3D_OK;
929 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
930 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
931 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
934 IWineD3DVolumeImpl *object;
935 HRESULT hr;
937 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
938 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
941 if (!object)
943 ERR("Out of memory\n");
944 *ppVolume = NULL;
945 return WINED3DERR_OUTOFVIDEOMEMORY;
948 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
949 if (FAILED(hr))
951 WARN("Failed to initialize volume, returning %#x.\n", hr);
952 HeapFree(GetProcessHeap(), 0, object);
953 return hr;
956 TRACE("(%p) : Created volume %p.\n", This, object);
957 *ppVolume = (IWineD3DVolume *)object;
959 return WINED3D_OK;
962 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
963 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
964 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
967 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
968 HRESULT hr;
970 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
971 if (!object)
973 ERR("Out of memory\n");
974 *ppCubeTexture = NULL;
975 return WINED3DERR_OUTOFVIDEOMEMORY;
978 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
979 if (FAILED(hr))
981 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
982 HeapFree(GetProcessHeap(), 0, object);
983 *ppCubeTexture = NULL;
984 return hr;
987 TRACE("(%p) : Created Cube Texture %p\n", This, object);
988 *ppCubeTexture = (IWineD3DCubeTexture *)object;
990 return WINED3D_OK;
993 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
994 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 IWineD3DQueryImpl *object;
998 HRESULT hr;
1000 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1002 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1003 if (!object)
1005 ERR("Failed to allocate query memory.\n");
1006 return E_OUTOFMEMORY;
1009 hr = query_init(object, This, type, parent);
1010 if (FAILED(hr))
1012 WARN("Failed to initialize query, hr %#x.\n", hr);
1013 HeapFree(GetProcessHeap(), 0, object);
1014 return hr;
1017 TRACE("Created query %p.\n", object);
1018 *query = (IWineD3DQuery *)object;
1020 return WINED3D_OK;
1023 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1024 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1025 IUnknown *parent, WINED3DSURFTYPE surface_type)
1027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1028 IWineD3DSwapChainImpl *object;
1029 HRESULT hr;
1031 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1032 iface, present_parameters, swapchain, parent, surface_type);
1034 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1035 if (!object)
1037 ERR("Failed to allocate swapchain memory.\n");
1038 return E_OUTOFMEMORY;
1041 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1042 if (FAILED(hr))
1044 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1045 HeapFree(GetProcessHeap(), 0, object);
1046 return hr;
1049 TRACE("Created swapchain %p.\n", object);
1050 *swapchain = (IWineD3DSwapChain *)object;
1052 return WINED3D_OK;
1055 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1056 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1058 TRACE("(%p)\n", This);
1060 return This->NumberOfSwapChains;
1063 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1065 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1067 if(iSwapChain < This->NumberOfSwapChains) {
1068 *pSwapChain = This->swapchains[iSwapChain];
1069 IWineD3DSwapChain_AddRef(*pSwapChain);
1070 TRACE("(%p) returning %p\n", This, *pSwapChain);
1071 return WINED3D_OK;
1072 } else {
1073 TRACE("Swapchain out of range\n");
1074 *pSwapChain = NULL;
1075 return WINED3DERR_INVALIDCALL;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1080 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1081 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1084 IWineD3DVertexDeclarationImpl *object = NULL;
1085 HRESULT hr;
1087 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1088 iface, declaration, parent, elements, element_count);
1090 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1091 if(!object)
1093 ERR("Failed to allocate vertex declaration memory.\n");
1094 return E_OUTOFMEMORY;
1097 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1098 if (FAILED(hr))
1100 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1101 HeapFree(GetProcessHeap(), 0, object);
1102 return hr;
1105 TRACE("Created vertex declaration %p.\n", object);
1106 *declaration = (IWineD3DVertexDeclaration *)object;
1108 return WINED3D_OK;
1111 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1112 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1114 unsigned int idx, idx2;
1115 unsigned int offset;
1116 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1117 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1118 BOOL has_blend_idx = has_blend &&
1119 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1120 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1121 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1122 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1123 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1124 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1125 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1127 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1128 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1129 WINED3DVERTEXELEMENT *elements = NULL;
1131 unsigned int size;
1132 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1133 if (has_blend_idx) num_blends--;
1135 /* Compute declaration size */
1136 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1137 has_psize + has_diffuse + has_specular + num_textures;
1139 /* convert the declaration */
1140 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1141 if (!elements) return ~0U;
1143 idx = 0;
1144 if (has_pos) {
1145 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1146 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1147 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1149 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1150 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1151 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1153 else {
1154 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1155 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1157 elements[idx].usage_idx = 0;
1158 idx++;
1160 if (has_blend && (num_blends > 0)) {
1161 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1162 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1163 else {
1164 switch(num_blends) {
1165 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1166 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1167 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1168 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1169 default:
1170 ERR("Unexpected amount of blend values: %u\n", num_blends);
1173 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1174 elements[idx].usage_idx = 0;
1175 idx++;
1177 if (has_blend_idx) {
1178 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1179 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1180 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1181 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1182 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1183 else
1184 elements[idx].format = WINED3DFMT_R32_FLOAT;
1185 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1186 elements[idx].usage_idx = 0;
1187 idx++;
1189 if (has_normal) {
1190 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1191 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1192 elements[idx].usage_idx = 0;
1193 idx++;
1195 if (has_psize) {
1196 elements[idx].format = WINED3DFMT_R32_FLOAT;
1197 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1198 elements[idx].usage_idx = 0;
1199 idx++;
1201 if (has_diffuse) {
1202 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1203 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1204 elements[idx].usage_idx = 0;
1205 idx++;
1207 if (has_specular) {
1208 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1209 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1210 elements[idx].usage_idx = 1;
1211 idx++;
1213 for (idx2 = 0; idx2 < num_textures; idx2++) {
1214 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1215 switch (numcoords) {
1216 case WINED3DFVF_TEXTUREFORMAT1:
1217 elements[idx].format = WINED3DFMT_R32_FLOAT;
1218 break;
1219 case WINED3DFVF_TEXTUREFORMAT2:
1220 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1221 break;
1222 case WINED3DFVF_TEXTUREFORMAT3:
1223 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1224 break;
1225 case WINED3DFVF_TEXTUREFORMAT4:
1226 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1227 break;
1229 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1230 elements[idx].usage_idx = idx2;
1231 idx++;
1234 /* Now compute offsets, and initialize the rest of the fields */
1235 for (idx = 0, offset = 0; idx < size; ++idx)
1237 const struct wined3d_format_desc *format_desc = getFormatDescEntry(elements[idx].format,
1238 &This->adapter->gl_info);
1239 elements[idx].input_slot = 0;
1240 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1241 elements[idx].offset = offset;
1242 offset += format_desc->component_count * format_desc->component_size;
1245 *ppVertexElements = elements;
1246 return size;
1249 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1250 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1251 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1254 WINED3DVERTEXELEMENT *elements;
1255 unsigned int size;
1256 DWORD hr;
1258 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1260 size = ConvertFvfToDeclaration(This, fvf, &elements);
1261 if (size == ~0U) return E_OUTOFMEMORY;
1263 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1264 HeapFree(GetProcessHeap(), 0, elements);
1265 return hr;
1268 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1269 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1270 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1271 const struct wined3d_parent_ops *parent_ops)
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1274 IWineD3DVertexShaderImpl *object;
1275 HRESULT hr;
1277 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1278 if (!object)
1280 ERR("Failed to allocate shader memory.\n");
1281 return E_OUTOFMEMORY;
1284 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1285 if (FAILED(hr))
1287 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1288 HeapFree(GetProcessHeap(), 0, object);
1289 return hr;
1292 TRACE("Created vertex shader %p.\n", object);
1293 *ppVertexShader = (IWineD3DVertexShader *)object;
1295 return WINED3D_OK;
1298 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1299 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1300 IWineD3DGeometryShader **shader, IUnknown *parent,
1301 const struct wined3d_parent_ops *parent_ops)
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1304 struct wined3d_geometryshader *object;
1305 HRESULT hr;
1307 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1308 if (!object)
1310 ERR("Failed to allocate shader memory.\n");
1311 return E_OUTOFMEMORY;
1314 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1315 if (FAILED(hr))
1317 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1318 HeapFree(GetProcessHeap(), 0, object);
1319 return hr;
1322 TRACE("Created geometry shader %p.\n", object);
1323 *shader = (IWineD3DGeometryShader *)object;
1325 return WINED3D_OK;
1328 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1329 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1330 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1331 const struct wined3d_parent_ops *parent_ops)
1333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1334 IWineD3DPixelShaderImpl *object;
1335 HRESULT hr;
1337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1338 if (!object)
1340 ERR("Failed to allocate shader memory.\n");
1341 return E_OUTOFMEMORY;
1344 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1345 if (FAILED(hr))
1347 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1348 HeapFree(GetProcessHeap(), 0, object);
1349 return hr;
1352 TRACE("Created pixel shader %p.\n", object);
1353 *ppPixelShader = (IWineD3DPixelShader *)object;
1355 return WINED3D_OK;
1358 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1359 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1362 IWineD3DPaletteImpl *object;
1363 HRESULT hr;
1364 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1366 /* Create the new object */
1367 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1368 if(!object) {
1369 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1370 return E_OUTOFMEMORY;
1373 object->lpVtbl = &IWineD3DPalette_Vtbl;
1374 object->ref = 1;
1375 object->Flags = Flags;
1376 object->parent = Parent;
1377 object->device = This;
1378 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1379 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1381 if(!object->hpal) {
1382 HeapFree( GetProcessHeap(), 0, object);
1383 return E_OUTOFMEMORY;
1386 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1387 if(FAILED(hr)) {
1388 IWineD3DPalette_Release((IWineD3DPalette *) object);
1389 return hr;
1392 *Palette = (IWineD3DPalette *) object;
1394 return WINED3D_OK;
1397 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1398 HBITMAP hbm;
1399 BITMAP bm;
1400 HRESULT hr;
1401 HDC dcb = NULL, dcs = NULL;
1402 WINEDDCOLORKEY colorkey;
1404 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1405 if(hbm)
1407 GetObjectA(hbm, sizeof(BITMAP), &bm);
1408 dcb = CreateCompatibleDC(NULL);
1409 if(!dcb) goto out;
1410 SelectObject(dcb, hbm);
1412 else
1414 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1415 * couldn't be loaded
1417 memset(&bm, 0, sizeof(bm));
1418 bm.bmWidth = 32;
1419 bm.bmHeight = 32;
1422 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1423 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1424 NULL, &wined3d_null_parent_ops);
1425 if(FAILED(hr)) {
1426 ERR("Wine logo requested, but failed to create surface\n");
1427 goto out;
1430 if(dcb) {
1431 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1432 if(FAILED(hr)) goto out;
1433 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1434 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1436 colorkey.dwColorSpaceLowValue = 0;
1437 colorkey.dwColorSpaceHighValue = 0;
1438 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1439 } else {
1440 /* Fill the surface with a white color to show that wined3d is there */
1441 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1444 out:
1445 if (dcb) DeleteDC(dcb);
1446 if (hbm) DeleteObject(hbm);
1449 /* Context activation is done by the caller. */
1450 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1452 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1453 unsigned int i;
1454 /* Under DirectX you can have texture stage operations even if no texture is
1455 bound, whereas opengl will only do texture operations when a valid texture is
1456 bound. We emulate this by creating dummy textures and binding them to each
1457 texture stage, but disable all stages by default. Hence if a stage is enabled
1458 then the default texture will kick in until replaced by a SetTexture call */
1459 ENTER_GL();
1461 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1463 /* The dummy texture does not have client storage backing */
1464 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1465 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1468 for (i = 0; i < gl_info->limits.textures; ++i)
1470 GLubyte white = 255;
1472 /* Make appropriate texture active */
1473 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1474 checkGLcall("glActiveTextureARB");
1476 /* Generate an opengl texture name */
1477 glGenTextures(1, &This->dummyTextureName[i]);
1478 checkGLcall("glGenTextures");
1479 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1481 /* Generate a dummy 2d texture (not using 1d because they cause many
1482 * DRI drivers fall back to sw) */
1483 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1484 checkGLcall("glBindTexture");
1486 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1487 checkGLcall("glTexImage2D");
1490 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1492 /* Reenable because if supported it is enabled by default */
1493 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1494 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1497 LEAVE_GL();
1500 /* Context activation is done by the caller. */
1501 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1503 ENTER_GL();
1504 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1505 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1506 LEAVE_GL();
1508 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1511 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1513 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1515 if (!wined3d_register_window(window, device))
1517 ERR("Failed to register window %p.\n", window);
1518 return E_FAIL;
1521 device->focus_window = window;
1522 SetForegroundWindow(window);
1524 return WINED3D_OK;
1527 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1529 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1531 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1532 device->focus_window = NULL;
1535 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1536 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1539 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1540 IWineD3DSwapChainImpl *swapchain = NULL;
1541 struct wined3d_context *context;
1542 HRESULT hr;
1543 DWORD state;
1544 unsigned int i;
1546 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1548 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1549 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1551 TRACE("(%p) : Creating stateblock\n", This);
1552 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1553 hr = IWineD3DDevice_CreateStateBlock(iface,
1554 WINED3DSBT_INIT,
1555 (IWineD3DStateBlock **)&This->stateBlock,
1556 NULL);
1557 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1558 WARN("Failed to create stateblock\n");
1559 goto err_out;
1561 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1562 This->updateStateBlock = This->stateBlock;
1563 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1565 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1566 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1567 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1568 sizeof(GLenum) * gl_info->limits.buffers);
1570 This->NumberOfPalettes = 1;
1571 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1572 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1573 ERR("Out of memory!\n");
1574 hr = E_OUTOFMEMORY;
1575 goto err_out;
1577 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1578 if(!This->palettes[0]) {
1579 ERR("Out of memory!\n");
1580 hr = E_OUTOFMEMORY;
1581 goto err_out;
1583 for (i = 0; i < 256; ++i) {
1584 This->palettes[0][i].peRed = 0xFF;
1585 This->palettes[0][i].peGreen = 0xFF;
1586 This->palettes[0][i].peBlue = 0xFF;
1587 This->palettes[0][i].peFlags = 0xFF;
1589 This->currentPalette = 0;
1591 /* Initialize the texture unit mapping to a 1:1 mapping */
1592 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1594 if (state < gl_info->limits.fragment_samplers)
1596 This->texUnitMap[state] = state;
1597 This->rev_tex_unit_map[state] = state;
1598 } else {
1599 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1600 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1604 /* Setup the implicit swapchain. This also initializes a context. */
1605 TRACE("Creating implicit swapchain\n");
1606 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1607 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1608 if (FAILED(hr))
1610 WARN("Failed to create implicit swapchain\n");
1611 goto err_out;
1614 This->NumberOfSwapChains = 1;
1615 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1616 if(!This->swapchains) {
1617 ERR("Out of memory!\n");
1618 goto err_out;
1620 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1622 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1623 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1624 This->render_targets[0] = swapchain->backBuffer[0];
1626 else {
1627 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1628 This->render_targets[0] = swapchain->frontBuffer;
1630 IWineD3DSurface_AddRef(This->render_targets[0]);
1632 /* Depth Stencil support */
1633 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1634 if (NULL != This->stencilBufferTarget) {
1635 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1638 hr = This->shader_backend->shader_alloc_private(iface);
1639 if(FAILED(hr)) {
1640 TRACE("Shader private data couldn't be allocated\n");
1641 goto err_out;
1643 hr = This->frag_pipe->alloc_private(iface);
1644 if(FAILED(hr)) {
1645 TRACE("Fragment pipeline private data couldn't be allocated\n");
1646 goto err_out;
1648 hr = This->blitter->alloc_private(iface);
1649 if(FAILED(hr)) {
1650 TRACE("Blitter private data couldn't be allocated\n");
1651 goto err_out;
1654 /* Set up some starting GL setup */
1656 /* Setup all the devices defaults */
1657 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1659 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1661 create_dummy_textures(This);
1663 ENTER_GL();
1665 /* Initialize the current view state */
1666 This->view_ident = 1;
1667 This->contexts[0]->last_was_rhw = 0;
1668 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1669 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1671 switch(wined3d_settings.offscreen_rendering_mode) {
1672 case ORM_FBO:
1673 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1674 break;
1676 case ORM_BACKBUFFER:
1678 if (context_get_current()->aux_buffers > 0)
1680 TRACE("Using auxilliary buffer for offscreen rendering\n");
1681 This->offscreenBuffer = GL_AUX0;
1682 } else {
1683 TRACE("Using back buffer for offscreen rendering\n");
1684 This->offscreenBuffer = GL_BACK;
1689 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1690 LEAVE_GL();
1692 context_release(context);
1694 /* Clear the screen */
1695 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1696 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1697 0x00, 1.0f, 0);
1699 This->d3d_initialized = TRUE;
1701 if(wined3d_settings.logo) {
1702 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1704 This->highest_dirty_ps_const = 0;
1705 This->highest_dirty_vs_const = 0;
1706 return WINED3D_OK;
1708 err_out:
1709 HeapFree(GetProcessHeap(), 0, This->render_targets);
1710 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1711 HeapFree(GetProcessHeap(), 0, This->swapchains);
1712 This->NumberOfSwapChains = 0;
1713 if(This->palettes) {
1714 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1715 HeapFree(GetProcessHeap(), 0, This->palettes);
1717 This->NumberOfPalettes = 0;
1718 if(swapchain) {
1719 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1721 if(This->stateBlock) {
1722 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1723 This->stateBlock = NULL;
1725 if (This->blit_priv) {
1726 This->blitter->free_private(iface);
1728 if (This->fragment_priv) {
1729 This->frag_pipe->free_private(iface);
1731 if (This->shader_priv) {
1732 This->shader_backend->shader_free_private(iface);
1734 return hr;
1737 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1738 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1741 IWineD3DSwapChainImpl *swapchain = NULL;
1742 HRESULT hr;
1744 /* Setup the implicit swapchain */
1745 TRACE("Creating implicit swapchain\n");
1746 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1747 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1748 if (FAILED(hr))
1750 WARN("Failed to create implicit swapchain\n");
1751 goto err_out;
1754 This->NumberOfSwapChains = 1;
1755 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1756 if(!This->swapchains) {
1757 ERR("Out of memory!\n");
1758 goto err_out;
1760 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1761 return WINED3D_OK;
1763 err_out:
1764 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1765 return hr;
1768 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1770 IWineD3DResource_UnLoad(resource);
1771 IWineD3DResource_Release(resource);
1772 return WINED3D_OK;
1775 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1776 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1779 const struct wined3d_gl_info *gl_info;
1780 struct wined3d_context *context;
1781 int sampler;
1782 UINT i;
1783 TRACE("(%p)\n", This);
1785 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1787 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1788 * it was created. Thus make sure a context is active for the glDelete* calls
1790 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1791 gl_info = context->gl_info;
1793 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1795 /* Unload resources */
1796 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1798 TRACE("Deleting high order patches\n");
1799 for(i = 0; i < PATCHMAP_SIZE; i++) {
1800 struct list *e1, *e2;
1801 struct WineD3DRectPatch *patch;
1802 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1803 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1804 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1808 /* Delete the mouse cursor texture */
1809 if(This->cursorTexture) {
1810 ENTER_GL();
1811 glDeleteTextures(1, &This->cursorTexture);
1812 LEAVE_GL();
1813 This->cursorTexture = 0;
1816 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1817 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1819 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1820 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1823 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1824 * private data, it might contain opengl pointers
1826 if(This->depth_blt_texture) {
1827 ENTER_GL();
1828 glDeleteTextures(1, &This->depth_blt_texture);
1829 LEAVE_GL();
1830 This->depth_blt_texture = 0;
1832 if (This->depth_blt_rb) {
1833 ENTER_GL();
1834 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1835 LEAVE_GL();
1836 This->depth_blt_rb = 0;
1837 This->depth_blt_rb_w = 0;
1838 This->depth_blt_rb_h = 0;
1841 /* Release the update stateblock */
1842 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1843 if(This->updateStateBlock != This->stateBlock)
1844 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1846 This->updateStateBlock = NULL;
1848 { /* because were not doing proper internal refcounts releasing the primary state block
1849 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1850 to set this->stateBlock = NULL; first */
1851 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1852 This->stateBlock = NULL;
1854 /* Release the stateblock */
1855 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1856 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1860 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1861 This->blitter->free_private(iface);
1862 This->frag_pipe->free_private(iface);
1863 This->shader_backend->shader_free_private(iface);
1865 /* Release the buffers (with sanity checks)*/
1866 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1867 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1868 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1869 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1871 This->stencilBufferTarget = NULL;
1873 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1874 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1875 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1877 TRACE("Setting rendertarget to NULL\n");
1878 This->render_targets[0] = NULL;
1880 if (This->auto_depth_stencil_buffer) {
1881 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1883 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1885 This->auto_depth_stencil_buffer = NULL;
1888 context_release(context);
1890 for(i=0; i < This->NumberOfSwapChains; i++) {
1891 TRACE("Releasing the implicit swapchain %d\n", i);
1892 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1893 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1897 HeapFree(GetProcessHeap(), 0, This->swapchains);
1898 This->swapchains = NULL;
1899 This->NumberOfSwapChains = 0;
1901 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1902 HeapFree(GetProcessHeap(), 0, This->palettes);
1903 This->palettes = NULL;
1904 This->NumberOfPalettes = 0;
1906 HeapFree(GetProcessHeap(), 0, This->render_targets);
1907 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1908 This->render_targets = NULL;
1909 This->draw_buffers = NULL;
1911 This->d3d_initialized = FALSE;
1913 return WINED3D_OK;
1916 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1918 unsigned int i;
1920 for(i=0; i < This->NumberOfSwapChains; i++) {
1921 TRACE("Releasing the implicit swapchain %d\n", i);
1922 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1923 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1927 HeapFree(GetProcessHeap(), 0, This->swapchains);
1928 This->swapchains = NULL;
1929 This->NumberOfSwapChains = 0;
1930 return WINED3D_OK;
1933 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1934 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1935 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1937 * There is no way to deactivate thread safety once it is enabled.
1939 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1942 /*For now just store the flag(needed in case of ddraw) */
1943 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1946 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1947 const WINED3DDISPLAYMODE* pMode) {
1948 DEVMODEW devmode;
1949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1950 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1951 LONG ret;
1952 RECT clip_rc;
1954 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1956 /* Resize the screen even without a window:
1957 * The app could have unset it with SetCooperativeLevel, but not called
1958 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1959 * but we don't have any hwnd
1962 memset(&devmode, 0, sizeof(devmode));
1963 devmode.dmSize = sizeof(devmode);
1964 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1965 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1966 devmode.dmPelsWidth = pMode->Width;
1967 devmode.dmPelsHeight = pMode->Height;
1969 devmode.dmDisplayFrequency = pMode->RefreshRate;
1970 if (pMode->RefreshRate != 0) {
1971 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1974 /* Only change the mode if necessary */
1975 if( (This->ddraw_width == pMode->Width) &&
1976 (This->ddraw_height == pMode->Height) &&
1977 (This->ddraw_format == pMode->Format) &&
1978 (pMode->RefreshRate == 0) ) {
1979 return WINED3D_OK;
1982 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1983 if (ret != DISP_CHANGE_SUCCESSFUL) {
1984 if(devmode.dmDisplayFrequency != 0) {
1985 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1986 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1987 devmode.dmDisplayFrequency = 0;
1988 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1990 if(ret != DISP_CHANGE_SUCCESSFUL) {
1991 return WINED3DERR_NOTAVAILABLE;
1995 /* Store the new values */
1996 This->ddraw_width = pMode->Width;
1997 This->ddraw_height = pMode->Height;
1998 This->ddraw_format = pMode->Format;
2000 /* And finally clip mouse to our screen */
2001 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2002 ClipCursor(&clip_rc);
2004 return WINED3D_OK;
2007 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2009 *ppD3D = This->wined3d;
2010 TRACE("Returning %p.\n", *ppD3D);
2011 IWineD3D_AddRef(*ppD3D);
2012 return WINED3D_OK;
2015 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2018 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2019 (This->adapter->TextureRam/(1024*1024)),
2020 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2021 /* return simulated texture memory left */
2022 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2025 /*****
2026 * Get / Set Stream Source
2027 *****/
2028 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2029 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2032 IWineD3DBuffer *oldSrc;
2034 if (StreamNumber >= MAX_STREAMS) {
2035 WARN("Stream out of range %d\n", StreamNumber);
2036 return WINED3DERR_INVALIDCALL;
2037 } else if(OffsetInBytes & 0x3) {
2038 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2039 return WINED3DERR_INVALIDCALL;
2042 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2043 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2045 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2047 if(oldSrc == pStreamData &&
2048 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2049 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2050 TRACE("Application is setting the old values over, nothing to do\n");
2051 return WINED3D_OK;
2054 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2055 if (pStreamData) {
2056 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2057 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2060 /* Handle recording of state blocks */
2061 if (This->isRecordingState) {
2062 TRACE("Recording... not performing anything\n");
2063 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2064 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2065 return WINED3D_OK;
2068 if (pStreamData != NULL) {
2069 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2070 IWineD3DBuffer_AddRef(pStreamData);
2072 if (oldSrc != NULL) {
2073 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2074 IWineD3DBuffer_Release(oldSrc);
2077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2079 return WINED3D_OK;
2082 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2083 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2087 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2088 This->stateBlock->streamSource[StreamNumber],
2089 This->stateBlock->streamOffset[StreamNumber],
2090 This->stateBlock->streamStride[StreamNumber]);
2092 if (StreamNumber >= MAX_STREAMS) {
2093 WARN("Stream out of range %d\n", StreamNumber);
2094 return WINED3DERR_INVALIDCALL;
2096 *pStream = This->stateBlock->streamSource[StreamNumber];
2097 *pStride = This->stateBlock->streamStride[StreamNumber];
2098 if (pOffset) {
2099 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2102 if (*pStream != NULL) {
2103 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2105 return WINED3D_OK;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2110 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2111 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2113 /* Verify input at least in d3d9 this is invalid*/
2114 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2115 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2116 return WINED3DERR_INVALIDCALL;
2118 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2119 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2120 return WINED3DERR_INVALIDCALL;
2122 if( Divider == 0 ){
2123 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2124 return WINED3DERR_INVALIDCALL;
2127 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2128 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2130 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2131 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2133 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2134 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2138 return WINED3D_OK;
2141 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2144 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2145 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2147 TRACE("(%p) : returning %d\n", This, *Divider);
2149 return WINED3D_OK;
2152 /*****
2153 * Get / Set & Multiply Transform
2154 *****/
2155 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2158 /* Most of this routine, comments included copied from ddraw tree initially: */
2159 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2161 /* Handle recording of state blocks */
2162 if (This->isRecordingState) {
2163 TRACE("Recording... not performing anything\n");
2164 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2165 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2166 return WINED3D_OK;
2170 * If the new matrix is the same as the current one,
2171 * we cut off any further processing. this seems to be a reasonable
2172 * optimization because as was noticed, some apps (warcraft3 for example)
2173 * tend towards setting the same matrix repeatedly for some reason.
2175 * From here on we assume that the new matrix is different, wherever it matters.
2177 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2178 TRACE("The app is setting the same matrix over again\n");
2179 return WINED3D_OK;
2180 } else {
2181 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2185 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2186 where ViewMat = Camera space, WorldMat = world space.
2188 In OpenGL, camera and world space is combined into GL_MODELVIEW
2189 matrix. The Projection matrix stay projection matrix.
2192 /* Capture the times we can just ignore the change for now */
2193 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2194 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2195 /* Handled by the state manager */
2198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2199 return WINED3D_OK;
2202 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2204 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2205 *pMatrix = This->stateBlock->transforms[State];
2206 return WINED3D_OK;
2209 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2210 const WINED3DMATRIX *mat = NULL;
2211 WINED3DMATRIX temp;
2213 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2214 * below means it will be recorded in a state block change, but it
2215 * works regardless where it is recorded.
2216 * If this is found to be wrong, change to StateBlock.
2218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2221 if (State <= HIGHEST_TRANSFORMSTATE)
2223 mat = &This->updateStateBlock->transforms[State];
2224 } else {
2225 FIXME("Unhandled transform state!!\n");
2228 multiply_matrix(&temp, mat, pMatrix);
2230 /* Apply change via set transform - will reapply to eg. lights this way */
2231 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2234 /*****
2235 * Get / Set Light
2236 *****/
2237 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2238 you can reference any indexes you want as long as that number max are enabled at any
2239 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2240 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2241 but when recording, just build a chain pretty much of commands to be replayed. */
2243 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2244 float rho;
2245 struct wined3d_light_info *object = NULL;
2246 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2247 struct list *e;
2249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2250 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2252 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2253 * the gl driver.
2255 if(!pLight) {
2256 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2257 return WINED3DERR_INVALIDCALL;
2260 switch(pLight->Type) {
2261 case WINED3DLIGHT_POINT:
2262 case WINED3DLIGHT_SPOT:
2263 case WINED3DLIGHT_PARALLELPOINT:
2264 case WINED3DLIGHT_GLSPOT:
2265 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2266 * most wanted
2268 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2270 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2271 return WINED3DERR_INVALIDCALL;
2273 break;
2275 case WINED3DLIGHT_DIRECTIONAL:
2276 /* Ignores attenuation */
2277 break;
2279 default:
2280 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2281 return WINED3DERR_INVALIDCALL;
2284 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2286 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2287 if(object->OriginalIndex == Index) break;
2288 object = NULL;
2291 if(!object) {
2292 TRACE("Adding new light\n");
2293 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2294 if(!object) {
2295 ERR("Out of memory error when allocating a light\n");
2296 return E_OUTOFMEMORY;
2298 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2299 object->glIndex = -1;
2300 object->OriginalIndex = Index;
2303 /* Initialize the object */
2304 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,
2305 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2306 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2307 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2308 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2309 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2310 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2312 /* Save away the information */
2313 object->OriginalParms = *pLight;
2315 switch (pLight->Type) {
2316 case WINED3DLIGHT_POINT:
2317 /* Position */
2318 object->lightPosn[0] = pLight->Position.x;
2319 object->lightPosn[1] = pLight->Position.y;
2320 object->lightPosn[2] = pLight->Position.z;
2321 object->lightPosn[3] = 1.0f;
2322 object->cutoff = 180.0f;
2323 /* FIXME: Range */
2324 break;
2326 case WINED3DLIGHT_DIRECTIONAL:
2327 /* Direction */
2328 object->lightPosn[0] = -pLight->Direction.x;
2329 object->lightPosn[1] = -pLight->Direction.y;
2330 object->lightPosn[2] = -pLight->Direction.z;
2331 object->lightPosn[3] = 0.0f;
2332 object->exponent = 0.0f;
2333 object->cutoff = 180.0f;
2334 break;
2336 case WINED3DLIGHT_SPOT:
2337 /* Position */
2338 object->lightPosn[0] = pLight->Position.x;
2339 object->lightPosn[1] = pLight->Position.y;
2340 object->lightPosn[2] = pLight->Position.z;
2341 object->lightPosn[3] = 1.0f;
2343 /* Direction */
2344 object->lightDirn[0] = pLight->Direction.x;
2345 object->lightDirn[1] = pLight->Direction.y;
2346 object->lightDirn[2] = pLight->Direction.z;
2347 object->lightDirn[3] = 1.0f;
2350 * opengl-ish and d3d-ish spot lights use too different models for the
2351 * light "intensity" as a function of the angle towards the main light direction,
2352 * so we only can approximate very roughly.
2353 * however spot lights are rather rarely used in games (if ever used at all).
2354 * furthermore if still used, probably nobody pays attention to such details.
2356 if (pLight->Falloff == 0) {
2357 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2358 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2359 * will always be 1.0 for both of them, and we don't have to care for the
2360 * rest of the rather complex calculation
2362 object->exponent = 0.0f;
2363 } else {
2364 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2365 if (rho < 0.0001f) rho = 0.0001f;
2366 object->exponent = -0.3f/logf(cosf(rho/2));
2368 if (object->exponent > 128.0f)
2370 object->exponent = 128.0f;
2372 object->cutoff = pLight->Phi*90/M_PI;
2374 /* FIXME: Range */
2375 break;
2377 default:
2378 FIXME("Unrecognized light type %d\n", pLight->Type);
2381 /* Update the live definitions if the light is currently assigned a glIndex */
2382 if (object->glIndex != -1 && !This->isRecordingState) {
2383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2385 return WINED3D_OK;
2388 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2390 struct wined3d_light_info *lightInfo = NULL;
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2393 struct list *e;
2394 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2396 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2398 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2399 if(lightInfo->OriginalIndex == Index) break;
2400 lightInfo = NULL;
2403 if (lightInfo == NULL) {
2404 TRACE("Light information requested but light not defined\n");
2405 return WINED3DERR_INVALIDCALL;
2408 *pLight = lightInfo->OriginalParms;
2409 return WINED3D_OK;
2412 /*****
2413 * Get / Set Light Enable
2414 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2415 *****/
2416 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2418 struct wined3d_light_info *lightInfo = NULL;
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2420 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2421 struct list *e;
2422 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2424 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2426 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2427 if(lightInfo->OriginalIndex == Index) break;
2428 lightInfo = NULL;
2430 TRACE("Found light: %p\n", lightInfo);
2432 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2433 if (lightInfo == NULL) {
2435 TRACE("Light enabled requested but light not defined, so defining one!\n");
2436 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2438 /* Search for it again! Should be fairly quick as near head of list */
2439 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2441 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2442 if(lightInfo->OriginalIndex == Index) break;
2443 lightInfo = NULL;
2445 if (lightInfo == NULL) {
2446 FIXME("Adding default lights has failed dismally\n");
2447 return WINED3DERR_INVALIDCALL;
2451 if(!Enable) {
2452 if(lightInfo->glIndex != -1) {
2453 if(!This->isRecordingState) {
2454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2457 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2458 lightInfo->glIndex = -1;
2459 } else {
2460 TRACE("Light already disabled, nothing to do\n");
2462 lightInfo->enabled = FALSE;
2463 } else {
2464 lightInfo->enabled = TRUE;
2465 if (lightInfo->glIndex != -1) {
2466 /* nop */
2467 TRACE("Nothing to do as light was enabled\n");
2468 } else {
2469 int i;
2470 /* Find a free gl light */
2471 for(i = 0; i < This->maxConcurrentLights; i++) {
2472 if(This->updateStateBlock->activeLights[i] == NULL) {
2473 This->updateStateBlock->activeLights[i] = lightInfo;
2474 lightInfo->glIndex = i;
2475 break;
2478 if(lightInfo->glIndex == -1) {
2479 /* Our tests show that Windows returns D3D_OK in this situation, even with
2480 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2481 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2482 * as well for those lights.
2484 * TODO: Test how this affects rendering
2486 WARN("Too many concurrently active lights\n");
2487 return WINED3D_OK;
2490 /* i == lightInfo->glIndex */
2491 if(!This->isRecordingState) {
2492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2497 return WINED3D_OK;
2500 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2502 struct wined3d_light_info *lightInfo = NULL;
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 struct list *e;
2505 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2506 TRACE("(%p) : for idx(%d)\n", This, Index);
2508 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2510 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2511 if(lightInfo->OriginalIndex == Index) break;
2512 lightInfo = NULL;
2515 if (lightInfo == NULL) {
2516 TRACE("Light enabled state requested but light not defined\n");
2517 return WINED3DERR_INVALIDCALL;
2519 /* true is 128 according to SetLightEnable */
2520 *pEnable = lightInfo->enabled ? 128 : 0;
2521 return WINED3D_OK;
2524 /*****
2525 * Get / Set Clip Planes
2526 *****/
2527 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2531 /* Validate Index */
2532 if (Index >= This->adapter->gl_info.limits.clipplanes)
2534 TRACE("Application has requested clipplane this device doesn't support\n");
2535 return WINED3DERR_INVALIDCALL;
2538 This->updateStateBlock->changed.clipplane |= 1 << Index;
2540 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2541 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2542 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2543 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2544 TRACE("Application is setting old values over, nothing to do\n");
2545 return WINED3D_OK;
2548 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2549 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2550 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2551 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2553 /* Handle recording of state blocks */
2554 if (This->isRecordingState) {
2555 TRACE("Recording... not performing anything\n");
2556 return WINED3D_OK;
2559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2561 return WINED3D_OK;
2564 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2566 TRACE("(%p) : for idx %d\n", This, Index);
2568 /* Validate Index */
2569 if (Index >= This->adapter->gl_info.limits.clipplanes)
2571 TRACE("Application has requested clipplane this device doesn't support\n");
2572 return WINED3DERR_INVALIDCALL;
2575 pPlane[0] = This->stateBlock->clipplane[Index][0];
2576 pPlane[1] = This->stateBlock->clipplane[Index][1];
2577 pPlane[2] = This->stateBlock->clipplane[Index][2];
2578 pPlane[3] = This->stateBlock->clipplane[Index][3];
2579 return WINED3D_OK;
2582 /*****
2583 * Get / Set Clip Plane Status
2584 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2585 *****/
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 FIXME("(%p) : stub\n", This);
2589 if (NULL == pClipStatus) {
2590 return WINED3DERR_INVALIDCALL;
2592 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2593 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2594 return WINED3D_OK;
2597 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 FIXME("(%p) : stub\n", This);
2600 if (NULL == pClipStatus) {
2601 return WINED3DERR_INVALIDCALL;
2603 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2604 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2605 return WINED3D_OK;
2608 /*****
2609 * Get / Set Material
2610 *****/
2611 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 This->updateStateBlock->changed.material = TRUE;
2615 This->updateStateBlock->material = *pMaterial;
2617 /* Handle recording of state blocks */
2618 if (This->isRecordingState) {
2619 TRACE("Recording... not performing anything\n");
2620 return WINED3D_OK;
2623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2624 return WINED3D_OK;
2627 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 *pMaterial = This->updateStateBlock->material;
2630 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2631 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2632 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2633 pMaterial->Ambient.b, pMaterial->Ambient.a);
2634 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2635 pMaterial->Specular.b, pMaterial->Specular.a);
2636 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2637 pMaterial->Emissive.b, pMaterial->Emissive.a);
2638 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2640 return WINED3D_OK;
2643 /*****
2644 * Get / Set Indices
2645 *****/
2646 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2647 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2650 IWineD3DBuffer *oldIdxs;
2652 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2653 oldIdxs = This->updateStateBlock->pIndexData;
2655 This->updateStateBlock->changed.indices = TRUE;
2656 This->updateStateBlock->pIndexData = pIndexData;
2657 This->updateStateBlock->IndexFmt = fmt;
2659 /* Handle recording of state blocks */
2660 if (This->isRecordingState) {
2661 TRACE("Recording... not performing anything\n");
2662 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2663 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2664 return WINED3D_OK;
2667 if(oldIdxs != pIndexData) {
2668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2669 if(pIndexData) {
2670 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2671 IWineD3DBuffer_AddRef(pIndexData);
2673 if(oldIdxs) {
2674 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2675 IWineD3DBuffer_Release(oldIdxs);
2679 return WINED3D_OK;
2682 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 *ppIndexData = This->stateBlock->pIndexData;
2688 /* up ref count on ppindexdata */
2689 if (*ppIndexData) {
2690 IWineD3DBuffer_AddRef(*ppIndexData);
2691 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2692 }else{
2693 TRACE("(%p) No index data set\n", This);
2695 TRACE("Returning %p\n", *ppIndexData);
2697 return WINED3D_OK;
2700 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2701 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 TRACE("(%p)->(%d)\n", This, BaseIndex);
2705 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2706 TRACE("Application is setting the old value over, nothing to do\n");
2707 return WINED3D_OK;
2710 This->updateStateBlock->baseVertexIndex = BaseIndex;
2712 if (This->isRecordingState) {
2713 TRACE("Recording... not performing anything\n");
2714 return WINED3D_OK;
2716 /* The base vertex index affects the stream sources */
2717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2718 return WINED3D_OK;
2721 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) : base_index %p\n", This, base_index);
2725 *base_index = This->stateBlock->baseVertexIndex;
2727 TRACE("Returning %u\n", *base_index);
2729 return WINED3D_OK;
2732 /*****
2733 * Get / Set Viewports
2734 *****/
2735 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2738 TRACE("(%p)\n", This);
2739 This->updateStateBlock->changed.viewport = TRUE;
2740 This->updateStateBlock->viewport = *pViewport;
2742 /* Handle recording of state blocks */
2743 if (This->isRecordingState) {
2744 TRACE("Recording... not performing anything\n");
2745 return WINED3D_OK;
2748 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2749 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2752 return WINED3D_OK;
2756 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p)\n", This);
2759 *pViewport = This->stateBlock->viewport;
2760 return WINED3D_OK;
2763 /*****
2764 * Get / Set Render States
2765 * TODO: Verify against dx9 definitions
2766 *****/
2767 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2770 DWORD oldValue = This->stateBlock->renderState[State];
2772 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2774 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2775 This->updateStateBlock->renderState[State] = Value;
2777 /* Handle recording of state blocks */
2778 if (This->isRecordingState) {
2779 TRACE("Recording... not performing anything\n");
2780 return WINED3D_OK;
2783 /* Compared here and not before the assignment to allow proper stateblock recording */
2784 if(Value == oldValue) {
2785 TRACE("Application is setting the old value over, nothing to do\n");
2786 } else {
2787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2790 return WINED3D_OK;
2793 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2796 *pValue = This->stateBlock->renderState[State];
2797 return WINED3D_OK;
2800 /*****
2801 * Get / Set Sampler States
2802 * TODO: Verify against dx9 definitions
2803 *****/
2805 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 DWORD oldValue;
2809 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2810 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2812 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2813 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2816 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2817 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2818 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2821 * SetSampler is designed to allow for more than the standard up to 8 textures
2822 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2823 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2825 * http://developer.nvidia.com/object/General_FAQ.html#t6
2827 * There are two new settings for GForce
2828 * the sampler one:
2829 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2830 * and the texture one:
2831 * GL_MAX_TEXTURE_COORDS_ARB.
2832 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2833 ******************/
2835 oldValue = This->stateBlock->samplerState[Sampler][Type];
2836 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2837 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2839 /* Handle recording of state blocks */
2840 if (This->isRecordingState) {
2841 TRACE("Recording... not performing anything\n");
2842 return WINED3D_OK;
2845 if(oldValue == Value) {
2846 TRACE("Application is setting the old value over, nothing to do\n");
2847 return WINED3D_OK;
2850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2852 return WINED3D_OK;
2855 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2859 This, Sampler, debug_d3dsamplerstate(Type), Type);
2861 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2862 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2865 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2866 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2867 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2869 *Value = This->stateBlock->samplerState[Sampler][Type];
2870 TRACE("(%p) : Returning %#x\n", This, *Value);
2872 return WINED3D_OK;
2875 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 This->updateStateBlock->changed.scissorRect = TRUE;
2879 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2880 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2881 return WINED3D_OK;
2883 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2885 if(This->isRecordingState) {
2886 TRACE("Recording... not performing anything\n");
2887 return WINED3D_OK;
2890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2892 return WINED3D_OK;
2895 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 *pRect = This->updateStateBlock->scissorRect;
2899 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2900 return WINED3D_OK;
2903 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2905 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2907 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2909 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2910 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2912 This->updateStateBlock->vertexDecl = pDecl;
2913 This->updateStateBlock->changed.vertexDecl = TRUE;
2915 if (This->isRecordingState) {
2916 TRACE("Recording... not performing anything\n");
2917 return WINED3D_OK;
2918 } else if(pDecl == oldDecl) {
2919 /* Checked after the assignment to allow proper stateblock recording */
2920 TRACE("Application is setting the old declaration over, nothing to do\n");
2921 return WINED3D_OK;
2924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2925 return WINED3D_OK;
2928 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2933 *ppDecl = This->stateBlock->vertexDecl;
2934 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2935 return WINED3D_OK;
2938 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2942 This->updateStateBlock->vertexShader = pShader;
2943 This->updateStateBlock->changed.vertexShader = TRUE;
2945 if (This->isRecordingState) {
2946 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2947 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2948 TRACE("Recording... not performing anything\n");
2949 return WINED3D_OK;
2950 } else if(oldShader == pShader) {
2951 /* Checked here to allow proper stateblock recording */
2952 TRACE("App is setting the old shader over, nothing to do\n");
2953 return WINED3D_OK;
2956 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2957 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2958 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2962 return WINED3D_OK;
2965 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2968 if (NULL == ppShader) {
2969 return WINED3DERR_INVALIDCALL;
2971 *ppShader = This->stateBlock->vertexShader;
2972 if( NULL != *ppShader)
2973 IWineD3DVertexShader_AddRef(*ppShader);
2975 TRACE("(%p) : returning %p\n", This, *ppShader);
2976 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2980 IWineD3DDevice *iface,
2981 UINT start,
2982 CONST BOOL *srcData,
2983 UINT count) {
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2988 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2989 iface, srcData, start, count);
2991 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2993 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2994 for (i = 0; i < cnt; i++)
2995 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2997 for (i = start; i < cnt + start; ++i) {
2998 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3001 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3003 return WINED3D_OK;
3006 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3007 IWineD3DDevice *iface,
3008 UINT start,
3009 BOOL *dstData,
3010 UINT count) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 int cnt = min(count, MAX_CONST_B - start);
3015 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3016 iface, dstData, start, count);
3018 if (dstData == NULL || cnt < 0)
3019 return WINED3DERR_INVALIDCALL;
3021 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3022 return WINED3D_OK;
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3026 IWineD3DDevice *iface,
3027 UINT start,
3028 CONST int *srcData,
3029 UINT count) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3035 iface, srcData, start, count);
3037 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3039 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3040 for (i = 0; i < cnt; i++)
3041 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3042 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3044 for (i = start; i < cnt + start; ++i) {
3045 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3048 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3050 return WINED3D_OK;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3054 IWineD3DDevice *iface,
3055 UINT start,
3056 int *dstData,
3057 UINT count) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 int cnt = min(count, MAX_CONST_I - start);
3062 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3063 iface, dstData, start, count);
3065 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3066 return WINED3DERR_INVALIDCALL;
3068 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3069 return WINED3D_OK;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3073 IWineD3DDevice *iface,
3074 UINT start,
3075 CONST float *srcData,
3076 UINT count) {
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 UINT i;
3081 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3082 iface, srcData, start, count);
3084 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3085 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3086 return WINED3DERR_INVALIDCALL;
3088 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3089 if(TRACE_ON(d3d)) {
3090 for (i = 0; i < count; i++)
3091 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3092 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3095 if (!This->isRecordingState)
3097 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3101 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3102 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3104 return WINED3D_OK;
3107 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3108 IWineD3DDevice *iface,
3109 UINT start,
3110 float *dstData,
3111 UINT count) {
3113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3114 int cnt = min(count, This->d3d_vshader_constantF - start);
3116 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3117 iface, dstData, start, count);
3119 if (dstData == NULL || cnt < 0)
3120 return WINED3DERR_INVALIDCALL;
3122 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3123 return WINED3D_OK;
3126 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3127 DWORD i;
3128 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3134 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3136 DWORD i = This->rev_tex_unit_map[unit];
3137 DWORD j = This->texUnitMap[stage];
3139 This->texUnitMap[stage] = unit;
3140 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3142 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3145 This->rev_tex_unit_map[unit] = stage;
3146 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3148 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3152 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3153 int i;
3155 This->fixed_function_usage_map = 0;
3156 for (i = 0; i < MAX_TEXTURES; ++i) {
3157 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3158 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3159 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3160 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3161 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3162 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3163 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3164 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3166 if (color_op == WINED3DTOP_DISABLE) {
3167 /* Not used, and disable higher stages */
3168 break;
3171 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3172 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3173 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3174 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3175 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3176 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3177 This->fixed_function_usage_map |= (1 << i);
3180 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3181 This->fixed_function_usage_map |= (1 << (i + 1));
3186 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3188 unsigned int i, tex;
3189 WORD ffu_map;
3191 device_update_fixed_function_usage_map(This);
3192 ffu_map = This->fixed_function_usage_map;
3194 if (This->max_ffp_textures == gl_info->limits.texture_stages
3195 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3197 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3199 if (!(ffu_map & 1)) continue;
3201 if (This->texUnitMap[i] != i) {
3202 device_map_stage(This, i, i);
3203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3204 markTextureStagesDirty(This, i);
3207 return;
3210 /* Now work out the mapping */
3211 tex = 0;
3212 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3214 if (!(ffu_map & 1)) continue;
3216 if (This->texUnitMap[i] != tex) {
3217 device_map_stage(This, i, tex);
3218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3219 markTextureStagesDirty(This, i);
3222 ++tex;
3226 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3228 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3229 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3230 unsigned int i;
3232 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3233 if (sampler_type[i] && This->texUnitMap[i] != i)
3235 device_map_stage(This, i, i);
3236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3237 if (i < gl_info->limits.texture_stages)
3239 markTextureStagesDirty(This, i);
3245 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3246 const DWORD *vshader_sampler_tokens, DWORD unit)
3248 DWORD current_mapping = This->rev_tex_unit_map[unit];
3250 /* Not currently used */
3251 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3253 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3254 /* Used by a fragment sampler */
3256 if (!pshader_sampler_tokens) {
3257 /* No pixel shader, check fixed function */
3258 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3261 /* Pixel shader, check the shader's sampler map */
3262 return !pshader_sampler_tokens[current_mapping];
3265 /* Used by a vertex sampler */
3266 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3269 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3271 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3272 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3273 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3274 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3275 int i;
3277 if (ps) {
3278 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3280 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3281 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3282 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3285 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3286 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3287 if (vshader_sampler_type[i])
3289 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3291 /* Already mapped somewhere */
3292 continue;
3295 while (start >= 0) {
3296 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3298 device_map_stage(This, vsampler_idx, start);
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3301 --start;
3302 break;
3305 --start;
3311 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3313 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3314 BOOL vs = use_vs(This->stateBlock);
3315 BOOL ps = use_ps(This->stateBlock);
3317 * Rules are:
3318 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3319 * that would be really messy and require shader recompilation
3320 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3321 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3323 if (ps) device_map_psamplers(This, gl_info);
3324 else device_map_fixed_function_samplers(This, gl_info);
3326 if (vs) device_map_vsamplers(This, ps, gl_info);
3329 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3332 This->updateStateBlock->pixelShader = pShader;
3333 This->updateStateBlock->changed.pixelShader = TRUE;
3335 /* Handle recording of state blocks */
3336 if (This->isRecordingState) {
3337 TRACE("Recording... not performing anything\n");
3340 if (This->isRecordingState) {
3341 TRACE("Recording... not performing anything\n");
3342 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3343 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3344 return WINED3D_OK;
3347 if(pShader == oldShader) {
3348 TRACE("App is setting the old pixel shader over, nothing to do\n");
3349 return WINED3D_OK;
3352 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3353 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3355 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 if (NULL == ppShader) {
3365 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3366 return WINED3DERR_INVALIDCALL;
3369 *ppShader = This->stateBlock->pixelShader;
3370 if (NULL != *ppShader) {
3371 IWineD3DPixelShader_AddRef(*ppShader);
3373 TRACE("(%p) : returning %p\n", This, *ppShader);
3374 return WINED3D_OK;
3377 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3378 IWineD3DDevice *iface,
3379 UINT start,
3380 CONST BOOL *srcData,
3381 UINT count) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3386 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3387 iface, srcData, start, count);
3389 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3391 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3392 for (i = 0; i < cnt; i++)
3393 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3395 for (i = start; i < cnt + start; ++i) {
3396 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3399 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3401 return WINED3D_OK;
3404 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3405 IWineD3DDevice *iface,
3406 UINT start,
3407 BOOL *dstData,
3408 UINT count) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 int cnt = min(count, MAX_CONST_B - start);
3413 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3414 iface, dstData, start, count);
3416 if (dstData == NULL || cnt < 0)
3417 return WINED3DERR_INVALIDCALL;
3419 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3420 return WINED3D_OK;
3423 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3424 IWineD3DDevice *iface,
3425 UINT start,
3426 CONST int *srcData,
3427 UINT count) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3432 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3433 iface, srcData, start, count);
3435 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3437 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3438 for (i = 0; i < cnt; i++)
3439 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3440 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3442 for (i = start; i < cnt + start; ++i) {
3443 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3446 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3448 return WINED3D_OK;
3451 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3452 IWineD3DDevice *iface,
3453 UINT start,
3454 int *dstData,
3455 UINT count) {
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458 int cnt = min(count, MAX_CONST_I - start);
3460 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3461 iface, dstData, start, count);
3463 if (dstData == NULL || cnt < 0)
3464 return WINED3DERR_INVALIDCALL;
3466 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3471 IWineD3DDevice *iface,
3472 UINT start,
3473 CONST float *srcData,
3474 UINT count) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 UINT i;
3479 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3480 iface, srcData, start, count);
3482 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3483 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3484 return WINED3DERR_INVALIDCALL;
3486 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3487 if(TRACE_ON(d3d)) {
3488 for (i = 0; i < count; i++)
3489 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3490 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3493 if (!This->isRecordingState)
3495 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3499 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3500 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3502 return WINED3D_OK;
3505 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3506 IWineD3DDevice *iface,
3507 UINT start,
3508 float *dstData,
3509 UINT count) {
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3512 int cnt = min(count, This->d3d_pshader_constantF - start);
3514 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3515 iface, dstData, start, count);
3517 if (dstData == NULL || cnt < 0)
3518 return WINED3DERR_INVALIDCALL;
3520 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3521 return WINED3D_OK;
3524 /* Context activation is done by the caller. */
3525 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3526 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3527 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3528 DWORD DestFVF)
3530 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3531 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3532 unsigned int i;
3533 WINED3DVIEWPORT vp;
3534 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3535 BOOL doClip;
3536 DWORD numTextures;
3538 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3540 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3543 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3545 ERR("Source has no position mask\n");
3546 return WINED3DERR_INVALIDCALL;
3549 /* We might access VBOs from this code, so hold the lock */
3550 ENTER_GL();
3552 if (dest->resource.allocatedMemory == NULL) {
3553 buffer_get_sysmem(dest);
3556 /* Get a pointer into the destination vbo(create one if none exists) and
3557 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3559 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3561 dest->flags |= WINED3D_BUFFER_CREATEBO;
3562 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3565 if (dest->buffer_object)
3567 unsigned char extrabytes = 0;
3568 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3569 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3570 * this may write 4 extra bytes beyond the area that should be written
3572 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3573 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3574 if(!dest_conv_addr) {
3575 ERR("Out of memory\n");
3576 /* Continue without storing converted vertices */
3578 dest_conv = dest_conv_addr;
3581 /* Should I clip?
3582 * a) WINED3DRS_CLIPPING is enabled
3583 * b) WINED3DVOP_CLIP is passed
3585 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3586 static BOOL warned = FALSE;
3588 * The clipping code is not quite correct. Some things need
3589 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3590 * so disable clipping for now.
3591 * (The graphics in Half-Life are broken, and my processvertices
3592 * test crashes with IDirect3DDevice3)
3593 doClip = TRUE;
3595 doClip = FALSE;
3596 if(!warned) {
3597 warned = TRUE;
3598 FIXME("Clipping is broken and disabled for now\n");
3600 } else doClip = FALSE;
3601 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3603 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3604 WINED3DTS_VIEW,
3605 &view_mat);
3606 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3607 WINED3DTS_PROJECTION,
3608 &proj_mat);
3609 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3610 WINED3DTS_WORLDMATRIX(0),
3611 &world_mat);
3613 TRACE("View mat:\n");
3614 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);
3615 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);
3616 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);
3617 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);
3619 TRACE("Proj mat:\n");
3620 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);
3621 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);
3622 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);
3623 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);
3625 TRACE("World mat:\n");
3626 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);
3627 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);
3628 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);
3629 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);
3631 /* Get the viewport */
3632 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3633 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3634 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3636 multiply_matrix(&mat,&view_mat,&world_mat);
3637 multiply_matrix(&mat,&proj_mat,&mat);
3639 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3641 for (i = 0; i < dwCount; i+= 1) {
3642 unsigned int tex_index;
3644 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3645 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3646 /* The position first */
3647 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3648 const float *p = (const float *)(element->data + i * element->stride);
3649 float x, y, z, rhw;
3650 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3652 /* Multiplication with world, view and projection matrix */
3653 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);
3654 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);
3655 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);
3656 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);
3658 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3660 /* WARNING: The following things are taken from d3d7 and were not yet checked
3661 * against d3d8 or d3d9!
3664 /* Clipping conditions: From msdn
3666 * A vertex is clipped if it does not match the following requirements
3667 * -rhw < x <= rhw
3668 * -rhw < y <= rhw
3669 * 0 < z <= rhw
3670 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3672 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3673 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3677 if( !doClip ||
3678 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3679 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3680 ( rhw > eps ) ) ) {
3682 /* "Normal" viewport transformation (not clipped)
3683 * 1) The values are divided by rhw
3684 * 2) The y axis is negative, so multiply it with -1
3685 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3686 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3687 * 4) Multiply x with Width/2 and add Width/2
3688 * 5) The same for the height
3689 * 6) Add the viewpoint X and Y to the 2D coordinates and
3690 * The minimum Z value to z
3691 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3693 * Well, basically it's simply a linear transformation into viewport
3694 * coordinates
3697 x /= rhw;
3698 y /= rhw;
3699 z /= rhw;
3701 y *= -1;
3703 x *= vp.Width / 2;
3704 y *= vp.Height / 2;
3705 z *= vp.MaxZ - vp.MinZ;
3707 x += vp.Width / 2 + vp.X;
3708 y += vp.Height / 2 + vp.Y;
3709 z += vp.MinZ;
3711 rhw = 1 / rhw;
3712 } else {
3713 /* That vertex got clipped
3714 * Contrary to OpenGL it is not dropped completely, it just
3715 * undergoes a different calculation.
3717 TRACE("Vertex got clipped\n");
3718 x += rhw;
3719 y += rhw;
3721 x /= 2;
3722 y /= 2;
3724 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3725 * outside of the main vertex buffer memory. That needs some more
3726 * investigation...
3730 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3733 ( (float *) dest_ptr)[0] = x;
3734 ( (float *) dest_ptr)[1] = y;
3735 ( (float *) dest_ptr)[2] = z;
3736 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3738 dest_ptr += 3 * sizeof(float);
3740 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3741 dest_ptr += sizeof(float);
3744 if(dest_conv) {
3745 float w = 1 / rhw;
3746 ( (float *) dest_conv)[0] = x * w;
3747 ( (float *) dest_conv)[1] = y * w;
3748 ( (float *) dest_conv)[2] = z * w;
3749 ( (float *) dest_conv)[3] = w;
3751 dest_conv += 3 * sizeof(float);
3753 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3754 dest_conv += sizeof(float);
3758 if (DestFVF & WINED3DFVF_PSIZE) {
3759 dest_ptr += sizeof(DWORD);
3760 if(dest_conv) dest_conv += sizeof(DWORD);
3762 if (DestFVF & WINED3DFVF_NORMAL) {
3763 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3764 const float *normal = (const float *)(element->data + i * element->stride);
3765 /* AFAIK this should go into the lighting information */
3766 FIXME("Didn't expect the destination to have a normal\n");
3767 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3768 if(dest_conv) {
3769 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3773 if (DestFVF & WINED3DFVF_DIFFUSE) {
3774 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3775 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3776 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3778 static BOOL warned = FALSE;
3780 if(!warned) {
3781 ERR("No diffuse color in source, but destination has one\n");
3782 warned = TRUE;
3785 *( (DWORD *) dest_ptr) = 0xffffffff;
3786 dest_ptr += sizeof(DWORD);
3788 if(dest_conv) {
3789 *( (DWORD *) dest_conv) = 0xffffffff;
3790 dest_conv += sizeof(DWORD);
3793 else {
3794 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3795 if(dest_conv) {
3796 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3797 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3798 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3799 dest_conv += sizeof(DWORD);
3804 if (DestFVF & WINED3DFVF_SPECULAR)
3806 /* What's the color value in the feedback buffer? */
3807 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3808 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3809 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3811 static BOOL warned = FALSE;
3813 if(!warned) {
3814 ERR("No specular color in source, but destination has one\n");
3815 warned = TRUE;
3818 *( (DWORD *) dest_ptr) = 0xFF000000;
3819 dest_ptr += sizeof(DWORD);
3821 if(dest_conv) {
3822 *( (DWORD *) dest_conv) = 0xFF000000;
3823 dest_conv += sizeof(DWORD);
3826 else {
3827 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3828 if(dest_conv) {
3829 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3830 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3831 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3832 dest_conv += sizeof(DWORD);
3837 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3838 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3839 const float *tex_coord = (const float *)(element->data + i * element->stride);
3840 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3842 ERR("No source texture, but destination requests one\n");
3843 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3844 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3846 else {
3847 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3848 if(dest_conv) {
3849 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3855 if(dest_conv) {
3856 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3857 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3858 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3859 dwCount * get_flexible_vertex_size(DestFVF),
3860 dest_conv_addr));
3861 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3862 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3865 LEAVE_GL();
3867 return WINED3D_OK;
3869 #undef copy_and_next
3871 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3872 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3873 DWORD DestFVF)
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3876 struct wined3d_stream_info stream_info;
3877 struct wined3d_context *context;
3878 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3879 HRESULT hr;
3881 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3883 if(pVertexDecl) {
3884 ERR("Output vertex declaration not implemented yet\n");
3887 /* Need any context to write to the vbo. */
3888 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3890 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3891 * control the streamIsUP flag, thus restore it afterwards.
3893 This->stateBlock->streamIsUP = FALSE;
3894 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3895 This->stateBlock->streamIsUP = streamWasUP;
3897 if(vbo || SrcStartIndex) {
3898 unsigned int i;
3899 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3900 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3902 * Also get the start index in, but only loop over all elements if there's something to add at all.
3904 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3906 struct wined3d_stream_info_element *e;
3908 if (!(stream_info.use_map & (1 << i))) continue;
3910 e = &stream_info.elements[i];
3911 if (e->buffer_object)
3913 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3914 e->buffer_object = 0;
3915 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3916 ENTER_GL();
3917 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3918 vb->buffer_object = 0;
3919 LEAVE_GL();
3921 if (e->data) e->data += e->stride * SrcStartIndex;
3925 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3926 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3928 context_release(context);
3930 return hr;
3933 /*****
3934 * Get / Set Texture Stage States
3935 * TODO: Verify against dx9 definitions
3936 *****/
3937 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3939 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3940 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3942 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3944 if (Stage >= gl_info->limits.texture_stages)
3946 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3947 Stage, gl_info->limits.texture_stages - 1);
3948 return WINED3D_OK;
3951 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3952 This->updateStateBlock->textureState[Stage][Type] = Value;
3954 if (This->isRecordingState) {
3955 TRACE("Recording... not performing anything\n");
3956 return WINED3D_OK;
3959 /* Checked after the assignments to allow proper stateblock recording */
3960 if(oldValue == Value) {
3961 TRACE("App is setting the old value over, nothing to do\n");
3962 return WINED3D_OK;
3965 if(Stage > This->stateBlock->lowest_disabled_stage &&
3966 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3967 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3968 * Changes in other states are important on disabled stages too
3970 return WINED3D_OK;
3973 if(Type == WINED3DTSS_COLOROP) {
3974 unsigned int i;
3976 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3977 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3978 * they have to be disabled
3980 * The current stage is dirtified below.
3982 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3983 TRACE("Additionally dirtifying stage %u\n", i);
3984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3986 This->stateBlock->lowest_disabled_stage = Stage;
3987 TRACE("New lowest disabled: %u\n", Stage);
3988 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3989 /* Previously disabled stage enabled. Stages above it may need enabling
3990 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3991 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3993 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3996 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3998 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3999 break;
4001 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4004 This->stateBlock->lowest_disabled_stage = i;
4005 TRACE("New lowest disabled: %u\n", i);
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4011 return WINED3D_OK;
4014 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4017 *pValue = This->updateStateBlock->textureState[Stage][Type];
4018 return WINED3D_OK;
4021 /*****
4022 * Get / Set Texture
4023 *****/
4024 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4025 DWORD stage, IWineD3DBaseTexture *texture)
4027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4028 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4029 IWineD3DBaseTexture *prev;
4031 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4033 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4034 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4036 /* Windows accepts overflowing this array... we do not. */
4037 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4039 WARN("Ignoring invalid stage %u.\n", stage);
4040 return WINED3D_OK;
4043 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4044 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4046 WARN("Rejecting attempt to set scratch texture.\n");
4047 return WINED3DERR_INVALIDCALL;
4050 This->updateStateBlock->changed.textures |= 1 << stage;
4052 prev = This->updateStateBlock->textures[stage];
4053 TRACE("Previous texture %p.\n", prev);
4055 if (texture == prev)
4057 TRACE("App is setting the same texture again, nothing to do.\n");
4058 return WINED3D_OK;
4061 TRACE("Setting new texture to %p.\n", texture);
4062 This->updateStateBlock->textures[stage] = texture;
4064 if (This->isRecordingState)
4066 TRACE("Recording... not performing anything\n");
4068 if (texture) IWineD3DBaseTexture_AddRef(texture);
4069 if (prev) IWineD3DBaseTexture_Release(prev);
4071 return WINED3D_OK;
4074 if (texture)
4076 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4077 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4078 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4080 IWineD3DBaseTexture_AddRef(texture);
4082 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4087 if (!prev && stage < gl_info->limits.texture_stages)
4089 /* The source arguments for color and alpha ops have different
4090 * meanings when a NULL texture is bound, so the COLOROP and
4091 * ALPHAOP have to be dirtified. */
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4096 if (bind_count == 1) t->baseTexture.sampler = stage;
4099 if (prev)
4101 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4102 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4104 IWineD3DBaseTexture_Release(prev);
4106 if (!texture && stage < gl_info->limits.texture_stages)
4108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4112 if (bind_count && t->baseTexture.sampler == stage)
4114 unsigned int i;
4116 /* Search for other stages the texture is bound to. Shouldn't
4117 * happen if applications bind textures to a single stage only. */
4118 TRACE("Searching for other stages the texture is bound to.\n");
4119 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4121 if (This->updateStateBlock->textures[i] == prev)
4123 TRACE("Texture is also bound to stage %u.\n", i);
4124 t->baseTexture.sampler = i;
4125 break;
4131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4133 return WINED3D_OK;
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4141 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4142 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4145 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4146 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4147 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4150 *ppTexture=This->stateBlock->textures[Stage];
4151 if (*ppTexture)
4152 IWineD3DBaseTexture_AddRef(*ppTexture);
4154 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4156 return WINED3D_OK;
4159 /*****
4160 * Get Back Buffer
4161 *****/
4162 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4163 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4165 IWineD3DSwapChain *swapchain;
4166 HRESULT hr;
4168 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4169 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4171 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4172 if (FAILED(hr))
4174 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4175 return hr;
4178 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4179 IWineD3DSwapChain_Release(swapchain);
4180 if (FAILED(hr))
4182 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4183 return hr;
4186 return WINED3D_OK;
4189 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4191 WARN("(%p) : stub, calling idirect3d for now\n", This);
4192 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4195 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197 IWineD3DSwapChain *swapChain;
4198 HRESULT hr;
4200 if(iSwapChain > 0) {
4201 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4202 if (hr == WINED3D_OK) {
4203 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4204 IWineD3DSwapChain_Release(swapChain);
4205 } else {
4206 FIXME("(%p) Error getting display mode\n", This);
4208 } else {
4209 /* Don't read the real display mode,
4210 but return the stored mode instead. X11 can't change the color
4211 depth, and some apps are pretty angry if they SetDisplayMode from
4212 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4214 Also don't relay to the swapchain because with ddraw it's possible
4215 that there isn't a swapchain at all */
4216 pMode->Width = This->ddraw_width;
4217 pMode->Height = This->ddraw_height;
4218 pMode->Format = This->ddraw_format;
4219 pMode->RefreshRate = 0;
4220 hr = WINED3D_OK;
4223 return hr;
4226 /*****
4227 * Stateblock related functions
4228 *****/
4230 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4232 IWineD3DStateBlock *stateblock;
4233 HRESULT hr;
4235 TRACE("(%p)\n", This);
4237 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4239 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4240 if (FAILED(hr)) return hr;
4242 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4243 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4244 This->isRecordingState = TRUE;
4246 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4248 return WINED3D_OK;
4251 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4253 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4255 if (!This->isRecordingState) {
4256 WARN("(%p) not recording! returning error\n", This);
4257 *ppStateBlock = NULL;
4258 return WINED3DERR_INVALIDCALL;
4261 stateblock_init_contained_states(object);
4263 *ppStateBlock = (IWineD3DStateBlock*) object;
4264 This->isRecordingState = FALSE;
4265 This->updateStateBlock = This->stateBlock;
4266 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4267 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4268 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4269 return WINED3D_OK;
4272 /*****
4273 * Scene related functions
4274 *****/
4275 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4276 /* At the moment we have no need for any functionality at the beginning
4277 of a scene */
4278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4279 TRACE("(%p)\n", This);
4281 if(This->inScene) {
4282 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4283 return WINED3DERR_INVALIDCALL;
4285 This->inScene = TRUE;
4286 return WINED3D_OK;
4289 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4292 struct wined3d_context *context;
4294 TRACE("(%p)\n", This);
4296 if(!This->inScene) {
4297 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4298 return WINED3DERR_INVALIDCALL;
4301 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4302 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4303 wglFlush();
4304 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4305 * fails. */
4306 context_release(context);
4308 This->inScene = FALSE;
4309 return WINED3D_OK;
4312 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4313 const RECT *pSourceRect, const RECT *pDestRect,
4314 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4316 IWineD3DSwapChain *swapChain = NULL;
4317 int i;
4318 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4320 TRACE("iface %p.\n", iface);
4322 for(i = 0 ; i < swapchains ; i ++) {
4324 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4325 TRACE("presentinng chain %d, %p\n", i, swapChain);
4326 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4327 IWineD3DSwapChain_Release(swapChain);
4330 return WINED3D_OK;
4333 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4334 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4336 /* partial viewport*/
4337 if (viewport->X != 0 || viewport->Y != 0
4338 || viewport->Width < target->currentDesc.Width
4339 || viewport->Height < target->currentDesc.Height)
4340 return FALSE;
4342 /* partial scissor rect */
4343 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4344 || scissor_rect->right < target->currentDesc.Width
4345 || scissor_rect->bottom < target->currentDesc.Height))
4346 return FALSE;
4348 /* partial clear rect */
4349 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4350 || clear_rect->x2 < target->currentDesc.Width
4351 || clear_rect->y2 < target->currentDesc.Height))
4352 return FALSE;
4354 return TRUE;
4357 /* Not called from the VTable (internal subroutine) */
4358 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4359 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4361 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4362 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4363 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4364 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4365 GLbitfield glMask = 0;
4366 unsigned int i;
4367 WINED3DRECT curRect;
4368 RECT vp_rect;
4369 UINT drawable_width, drawable_height;
4370 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4371 struct wined3d_context *context;
4373 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4374 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4375 * for the cleared parts, and the untouched parts.
4377 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4378 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4379 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4380 * checking all this if the dest surface is in the drawable anyway.
4382 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4384 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4385 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4388 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4389 if (!context->valid)
4391 context_release(context);
4392 WARN("Invalid context, skipping clear.\n");
4393 return WINED3D_OK;
4396 target->get_drawable_size(context, &drawable_width, &drawable_height);
4398 ENTER_GL();
4400 /* Only set the values up once, as they are not changing */
4401 if (Flags & WINED3DCLEAR_STENCIL)
4403 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4405 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4408 glStencilMask(~0U);
4409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4410 glClearStencil(Stencil);
4411 checkGLcall("glClearStencil");
4412 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4415 if (Flags & WINED3DCLEAR_ZBUFFER)
4417 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4418 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4419 surface_load_ds_location(This->stencilBufferTarget, context, location);
4421 glDepthMask(GL_TRUE);
4422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4423 glClearDepth(Z);
4424 checkGLcall("glClearDepth");
4425 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4428 if (Flags & WINED3DCLEAR_TARGET)
4430 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4435 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4436 checkGLcall("glClearColor");
4437 glMask = glMask | GL_COLOR_BUFFER_BIT;
4440 vp_rect.left = vp->X;
4441 vp_rect.top = vp->Y;
4442 vp_rect.right = vp->X + vp->Width;
4443 vp_rect.bottom = vp->Y + vp->Height;
4444 if (!(Count > 0 && pRects)) {
4445 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4446 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4448 if (context->render_offscreen)
4450 glScissor(vp_rect.left, vp_rect.top,
4451 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4452 } else {
4453 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4454 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4456 checkGLcall("glScissor");
4457 glClear(glMask);
4458 checkGLcall("glClear");
4459 } else {
4460 /* Now process each rect in turn */
4461 for (i = 0; i < Count; i++) {
4462 /* Note gl uses lower left, width/height */
4463 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4464 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4465 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4467 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4468 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4469 curRect.x1, (target->currentDesc.Height - curRect.y2),
4470 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4472 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4473 * The rectangle is not cleared, no error is returned, but further rectanlges are
4474 * still cleared if they are valid
4476 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4477 TRACE("Rectangle with negative dimensions, ignoring\n");
4478 continue;
4481 if (context->render_offscreen)
4483 glScissor(curRect.x1, curRect.y1,
4484 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4485 } else {
4486 glScissor(curRect.x1, drawable_height - curRect.y2,
4487 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4489 checkGLcall("glScissor");
4491 glClear(glMask);
4492 checkGLcall("glClear");
4496 if (Flags & WINED3DCLEAR_TARGET)
4498 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4500 if (Flags & WINED3DCLEAR_ZBUFFER) {
4501 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4502 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4503 surface_modify_ds_location(This->stencilBufferTarget, location);
4506 LEAVE_GL();
4508 wglFlush(); /* Flush to ensure ordering across contexts. */
4510 context_release(context);
4512 return WINED3D_OK;
4515 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4516 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4520 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4521 Count, pRects, Flags, Color, Z, Stencil);
4523 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4524 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4525 /* TODO: What about depth stencil buffers without stencil bits? */
4526 return WINED3DERR_INVALIDCALL;
4529 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4532 /*****
4533 * Drawing functions
4534 *****/
4536 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4537 WINED3DPRIMITIVETYPE primitive_type)
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4541 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4543 This->updateStateBlock->changed.primitive_type = TRUE;
4544 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4547 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4548 WINED3DPRIMITIVETYPE *primitive_type)
4550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4552 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4554 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4556 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4559 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4563 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4565 if(!This->stateBlock->vertexDecl) {
4566 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4567 return WINED3DERR_INVALIDCALL;
4570 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4571 if(This->stateBlock->streamIsUP) {
4572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4573 This->stateBlock->streamIsUP = FALSE;
4576 if(This->stateBlock->loadBaseVertexIndex != 0) {
4577 This->stateBlock->loadBaseVertexIndex = 0;
4578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4580 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4581 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4582 return WINED3D_OK;
4585 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 UINT idxStride = 2;
4589 IWineD3DBuffer *pIB;
4590 GLuint vbo;
4592 pIB = This->stateBlock->pIndexData;
4593 if (!pIB) {
4594 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4595 * without an index buffer set. (The first time at least...)
4596 * D3D8 simply dies, but I doubt it can do much harm to return
4597 * D3DERR_INVALIDCALL there as well. */
4598 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4599 return WINED3DERR_INVALIDCALL;
4602 if(!This->stateBlock->vertexDecl) {
4603 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4604 return WINED3DERR_INVALIDCALL;
4607 if(This->stateBlock->streamIsUP) {
4608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4609 This->stateBlock->streamIsUP = FALSE;
4611 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4613 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4615 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4616 idxStride = 2;
4617 } else {
4618 idxStride = 4;
4621 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4622 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4626 drawPrimitive(iface, index_count, startIndex, idxStride,
4627 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4629 return WINED3D_OK;
4632 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4633 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4636 IWineD3DBuffer *vb;
4638 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4639 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4641 if(!This->stateBlock->vertexDecl) {
4642 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4643 return WINED3DERR_INVALIDCALL;
4646 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4647 vb = This->stateBlock->streamSource[0];
4648 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4649 if (vb) IWineD3DBuffer_Release(vb);
4650 This->stateBlock->streamOffset[0] = 0;
4651 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4652 This->stateBlock->streamIsUP = TRUE;
4653 This->stateBlock->loadBaseVertexIndex = 0;
4655 /* TODO: Only mark dirty if drawing from a different UP address */
4656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4658 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4660 /* MSDN specifies stream zero settings must be set to NULL */
4661 This->stateBlock->streamStride[0] = 0;
4662 This->stateBlock->streamSource[0] = NULL;
4664 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4665 * the new stream sources or use UP drawing again
4667 return WINED3D_OK;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4671 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4672 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4674 int idxStride;
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4676 IWineD3DBuffer *vb;
4677 IWineD3DBuffer *ib;
4679 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4680 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4682 if(!This->stateBlock->vertexDecl) {
4683 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4684 return WINED3DERR_INVALIDCALL;
4687 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4688 idxStride = 2;
4689 } else {
4690 idxStride = 4;
4693 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4694 vb = This->stateBlock->streamSource[0];
4695 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4696 if (vb) IWineD3DBuffer_Release(vb);
4697 This->stateBlock->streamIsUP = TRUE;
4698 This->stateBlock->streamOffset[0] = 0;
4699 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4701 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4702 This->stateBlock->baseVertexIndex = 0;
4703 This->stateBlock->loadBaseVertexIndex = 0;
4704 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4708 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4710 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4711 This->stateBlock->streamSource[0] = NULL;
4712 This->stateBlock->streamStride[0] = 0;
4713 ib = This->stateBlock->pIndexData;
4714 if(ib) {
4715 IWineD3DBuffer_Release(ib);
4716 This->stateBlock->pIndexData = NULL;
4718 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4719 * SetStreamSource to specify a vertex buffer
4722 return WINED3D_OK;
4725 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4726 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4730 /* Mark the state dirty until we have nicer tracking
4731 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4732 * that value.
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4736 This->stateBlock->baseVertexIndex = 0;
4737 This->up_strided = DrawPrimStrideData;
4738 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4739 This->up_strided = NULL;
4740 return WINED3D_OK;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4744 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4745 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4748 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4750 /* Mark the state dirty until we have nicer tracking
4751 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4752 * that value.
4754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4756 This->stateBlock->streamIsUP = TRUE;
4757 This->stateBlock->baseVertexIndex = 0;
4758 This->up_strided = DrawPrimStrideData;
4759 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4760 This->up_strided = NULL;
4761 return WINED3D_OK;
4764 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4765 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4766 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4768 WINED3DLOCKED_BOX src;
4769 WINED3DLOCKED_BOX dst;
4770 HRESULT hr;
4772 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4773 iface, pSourceVolume, pDestinationVolume);
4775 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4776 * dirtification to improve loading performance.
4778 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4779 if(FAILED(hr)) return hr;
4780 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4781 if(FAILED(hr)) {
4782 IWineD3DVolume_UnlockBox(pSourceVolume);
4783 return hr;
4786 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4788 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4789 if(FAILED(hr)) {
4790 IWineD3DVolume_UnlockBox(pSourceVolume);
4791 } else {
4792 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4794 return hr;
4797 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4798 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4800 unsigned int level_count, i;
4801 WINED3DRESOURCETYPE type;
4802 HRESULT hr;
4804 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4806 /* Verify that the source and destination textures are non-NULL. */
4807 if (!src_texture || !dst_texture)
4809 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4810 return WINED3DERR_INVALIDCALL;
4813 if (src_texture == dst_texture)
4815 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4816 return WINED3DERR_INVALIDCALL;
4819 /* Verify that the source and destination textures are the same type. */
4820 type = IWineD3DBaseTexture_GetType(src_texture);
4821 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4823 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4824 return WINED3DERR_INVALIDCALL;
4827 /* Check that both textures have the identical numbers of levels. */
4828 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4829 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4831 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4832 return WINED3DERR_INVALIDCALL;
4835 /* Make sure that the destination texture is loaded. */
4836 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4838 /* Update every surface level of the texture. */
4839 switch (type)
4841 case WINED3DRTYPE_TEXTURE:
4843 IWineD3DSurface *src_surface;
4844 IWineD3DSurface *dst_surface;
4846 for (i = 0; i < level_count; ++i)
4848 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4849 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4850 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4851 IWineD3DSurface_Release(dst_surface);
4852 IWineD3DSurface_Release(src_surface);
4853 if (FAILED(hr))
4855 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4856 return hr;
4859 break;
4862 case WINED3DRTYPE_CUBETEXTURE:
4864 IWineD3DSurface *src_surface;
4865 IWineD3DSurface *dst_surface;
4866 WINED3DCUBEMAP_FACES face;
4868 for (i = 0; i < level_count; ++i)
4870 /* Update each cube face. */
4871 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4873 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4874 face, i, &src_surface);
4875 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4876 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4877 face, i, &dst_surface);
4878 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4879 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4880 IWineD3DSurface_Release(dst_surface);
4881 IWineD3DSurface_Release(src_surface);
4882 if (FAILED(hr))
4884 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4885 return hr;
4889 break;
4892 case WINED3DRTYPE_VOLUMETEXTURE:
4894 IWineD3DVolume *src_volume;
4895 IWineD3DVolume *dst_volume;
4897 for (i = 0; i < level_count; ++i)
4899 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4900 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4901 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4902 IWineD3DVolume_Release(dst_volume);
4903 IWineD3DVolume_Release(src_volume);
4904 if (FAILED(hr))
4906 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4907 return hr;
4910 break;
4913 default:
4914 FIXME("Unsupported texture type %#x.\n", type);
4915 return WINED3DERR_INVALIDCALL;
4918 return WINED3D_OK;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4922 IWineD3DSwapChain *swapChain;
4923 HRESULT hr;
4924 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4925 if(hr == WINED3D_OK) {
4926 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4927 IWineD3DSwapChain_Release(swapChain);
4929 return hr;
4932 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 IWineD3DBaseTextureImpl *texture;
4935 DWORD i;
4937 TRACE("(%p) : %p\n", This, pNumPasses);
4939 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4940 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4941 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4942 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4944 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4945 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4946 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4949 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4950 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4952 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4953 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4954 return E_FAIL;
4956 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4957 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4958 return E_FAIL;
4960 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4961 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4962 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4963 return E_FAIL;
4967 /* return a sensible default */
4968 *pNumPasses = 1;
4970 TRACE("returning D3D_OK\n");
4971 return WINED3D_OK;
4974 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4976 int i;
4978 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4980 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4981 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4982 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4984 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4989 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4991 int j;
4992 UINT NewSize;
4993 PALETTEENTRY **palettes;
4995 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4997 if (PaletteNumber >= MAX_PALETTES) {
4998 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4999 return WINED3DERR_INVALIDCALL;
5002 if (PaletteNumber >= This->NumberOfPalettes) {
5003 NewSize = This->NumberOfPalettes;
5004 do {
5005 NewSize *= 2;
5006 } while(PaletteNumber >= NewSize);
5007 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5008 if (!palettes) {
5009 ERR("Out of memory!\n");
5010 return E_OUTOFMEMORY;
5012 This->palettes = palettes;
5013 This->NumberOfPalettes = NewSize;
5016 if (!This->palettes[PaletteNumber]) {
5017 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5018 if (!This->palettes[PaletteNumber]) {
5019 ERR("Out of memory!\n");
5020 return E_OUTOFMEMORY;
5024 for (j = 0; j < 256; ++j) {
5025 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5026 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5027 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5028 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5030 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5031 TRACE("(%p) : returning\n", This);
5032 return WINED3D_OK;
5035 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5037 int j;
5038 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5039 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5040 /* What happens in such situation isn't documented; Native seems to silently abort
5041 on such conditions. Return Invalid Call. */
5042 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5043 return WINED3DERR_INVALIDCALL;
5045 for (j = 0; j < 256; ++j) {
5046 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5047 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5048 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5049 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5051 TRACE("(%p) : returning\n", This);
5052 return WINED3D_OK;
5055 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5057 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5058 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5059 (tested with reference rasterizer). Return Invalid Call. */
5060 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5061 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5062 return WINED3DERR_INVALIDCALL;
5064 /*TODO: stateblocks */
5065 if (This->currentPalette != PaletteNumber) {
5066 This->currentPalette = PaletteNumber;
5067 dirtify_p8_texture_samplers(This);
5069 TRACE("(%p) : returning\n", This);
5070 return WINED3D_OK;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5075 if (PaletteNumber == NULL) {
5076 WARN("(%p) : returning Invalid Call\n", This);
5077 return WINED3DERR_INVALIDCALL;
5079 /*TODO: stateblocks */
5080 *PaletteNumber = This->currentPalette;
5081 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5082 return WINED3D_OK;
5085 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5087 static BOOL warned;
5088 if (!warned)
5090 FIXME("(%p) : stub\n", This);
5091 warned = TRUE;
5094 This->softwareVertexProcessing = bSoftware;
5095 return WINED3D_OK;
5099 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5101 static BOOL warned;
5102 if (!warned)
5104 FIXME("(%p) : stub\n", This);
5105 warned = TRUE;
5107 return This->softwareVertexProcessing;
5110 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5111 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5113 IWineD3DSwapChain *swapchain;
5114 HRESULT hr;
5116 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5117 iface, swapchain_idx, raster_status);
5119 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5120 if (FAILED(hr))
5122 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5123 return hr;
5126 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5127 IWineD3DSwapChain_Release(swapchain);
5128 if (FAILED(hr))
5130 WARN("Failed to get raster status, hr %#x.\n", hr);
5131 return hr;
5134 return WINED3D_OK;
5137 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5139 static BOOL warned;
5140 if(nSegments != 0.0f) {
5141 if (!warned)
5143 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5144 warned = TRUE;
5147 return WINED3D_OK;
5150 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5152 static BOOL warned;
5153 if (!warned)
5155 FIXME("iface %p stub!\n", iface);
5156 warned = TRUE;
5158 return 0.0f;
5161 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5162 IWineD3DSurface *src_surface, const RECT *src_rect,
5163 IWineD3DSurface *dst_surface, const POINT *dst_point)
5165 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5166 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5168 const struct wined3d_format_desc *src_format;
5169 const struct wined3d_format_desc *dst_format;
5170 struct wined3d_context *context;
5171 const unsigned char *data;
5172 UINT update_w, update_h;
5173 CONVERT_TYPES convert;
5174 UINT src_w, src_h;
5175 UINT dst_x, dst_y;
5176 DWORD sampler;
5177 GLenum dummy;
5178 int bpp;
5180 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s",
5181 iface, src_surface, wine_dbgstr_rect(src_rect),
5182 dst_surface, wine_dbgstr_point(dst_point));
5184 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5186 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5187 src_surface, dst_surface);
5188 return WINED3DERR_INVALIDCALL;
5191 src_format = src_impl->resource.format_desc;
5192 dst_format = dst_impl->resource.format_desc;
5194 if (src_format->format != dst_format->format)
5196 WARN("Source and destination surfaces should have the same format.\n");
5197 return WINED3DERR_INVALIDCALL;
5200 dst_x = dst_point ? dst_point->x : 0;
5201 dst_y = dst_point ? dst_point->y : 0;
5203 /* This call loads the OpenGL surface directly, instead of copying the
5204 * surface to the destination's sysmem copy. If surface conversion is
5205 * needed, use BltFast instead to copy in sysmem and use regular surface
5206 * loading. */
5207 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5208 if (convert != NO_CONVERSION)
5209 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5211 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5213 ENTER_GL();
5214 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5215 checkGLcall("glActiveTextureARB");
5216 LEAVE_GL();
5218 /* Make sure the surface is loaded and up to date */
5219 surface_internal_preload(dst_surface, SRGB_RGB);
5220 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5222 src_w = src_impl->currentDesc.Width;
5223 src_h = src_impl->currentDesc.Height;
5224 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5225 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5227 data = IWineD3DSurface_GetData(src_surface);
5228 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5230 ENTER_GL();
5232 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5234 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5235 UINT row_count = update_h / src_format->block_height;
5236 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5238 if (src_rect)
5240 data += (src_rect->top / src_format->block_height) * src_pitch;
5241 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5244 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5245 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5246 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5248 if (row_length == src_pitch)
5250 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5251 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5253 else
5255 UINT row, y;
5257 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5258 * can't use the unpack row length like below. */
5259 for (row = 0, y = dst_y; row < row_count; ++row)
5261 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5262 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5263 y += src_format->block_height;
5264 data += src_pitch;
5267 checkGLcall("glCompressedTexSubImage2DARB");
5269 else
5271 if (src_rect)
5273 data += src_rect->top * src_w * src_format->byte_count;
5274 data += src_rect->left * src_format->byte_count;
5277 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5278 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5279 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5281 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5282 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5283 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5284 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5285 checkGLcall("glTexSubImage2D");
5288 LEAVE_GL();
5289 context_release(context);
5291 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5292 sampler = This->rev_tex_unit_map[0];
5293 if (sampler != WINED3D_UNMAPPED_STAGE)
5295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5298 return WINED3D_OK;
5301 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5303 struct WineD3DRectPatch *patch;
5304 GLenum old_primitive_type;
5305 unsigned int i;
5306 struct list *e;
5307 BOOL found;
5308 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5310 if(!(Handle || pRectPatchInfo)) {
5311 /* TODO: Write a test for the return value, thus the FIXME */
5312 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5313 return WINED3DERR_INVALIDCALL;
5316 if(Handle) {
5317 i = PATCHMAP_HASHFUNC(Handle);
5318 found = FALSE;
5319 LIST_FOR_EACH(e, &This->patches[i]) {
5320 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5321 if(patch->Handle == Handle) {
5322 found = TRUE;
5323 break;
5327 if(!found) {
5328 TRACE("Patch does not exist. Creating a new one\n");
5329 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5330 patch->Handle = Handle;
5331 list_add_head(&This->patches[i], &patch->entry);
5332 } else {
5333 TRACE("Found existing patch %p\n", patch);
5335 } else {
5336 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5337 * attributes we have to tesselate, read back, and draw. This needs a patch
5338 * management structure instance. Create one.
5340 * A possible improvement is to check if a vertex shader is used, and if not directly
5341 * draw the patch.
5343 FIXME("Drawing an uncached patch. This is slow\n");
5344 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5347 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5348 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5349 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5350 HRESULT hr;
5351 TRACE("Tesselation density or patch info changed, retesselating\n");
5353 if(pRectPatchInfo) {
5354 patch->RectPatchInfo = *pRectPatchInfo;
5356 patch->numSegs[0] = pNumSegs[0];
5357 patch->numSegs[1] = pNumSegs[1];
5358 patch->numSegs[2] = pNumSegs[2];
5359 patch->numSegs[3] = pNumSegs[3];
5361 hr = tesselate_rectpatch(This, patch);
5362 if(FAILED(hr)) {
5363 WARN("Patch tesselation failed\n");
5365 /* Do not release the handle to store the params of the patch */
5366 if(!Handle) {
5367 HeapFree(GetProcessHeap(), 0, patch);
5369 return hr;
5373 This->currentPatch = patch;
5374 old_primitive_type = This->stateBlock->gl_primitive_type;
5375 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5376 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5377 This->stateBlock->gl_primitive_type = old_primitive_type;
5378 This->currentPatch = NULL;
5380 /* Destroy uncached patches */
5381 if(!Handle) {
5382 HeapFree(GetProcessHeap(), 0, patch->mem);
5383 HeapFree(GetProcessHeap(), 0, patch);
5385 return WINED3D_OK;
5388 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5389 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5391 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5392 iface, handle, segment_count, patch_info);
5394 return WINED3D_OK;
5397 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5399 int i;
5400 struct WineD3DRectPatch *patch;
5401 struct list *e;
5402 TRACE("(%p) Handle(%d)\n", This, Handle);
5404 i = PATCHMAP_HASHFUNC(Handle);
5405 LIST_FOR_EACH(e, &This->patches[i]) {
5406 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5407 if(patch->Handle == Handle) {
5408 TRACE("Deleting patch %p\n", patch);
5409 list_remove(&patch->entry);
5410 HeapFree(GetProcessHeap(), 0, patch->mem);
5411 HeapFree(GetProcessHeap(), 0, patch);
5412 return WINED3D_OK;
5416 /* TODO: Write a test for the return value */
5417 FIXME("Attempt to destroy nonexistent patch\n");
5418 return WINED3DERR_INVALIDCALL;
5421 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5422 const WINED3DRECT *rect, const float color[4])
5424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5425 struct wined3d_context *context;
5427 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5428 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5430 if (!surface_is_offscreen(surface))
5432 TRACE("Surface %p is onscreen\n", surface);
5434 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5435 ENTER_GL();
5436 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5437 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5439 else
5441 TRACE("Surface %p is offscreen\n", surface);
5443 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5444 ENTER_GL();
5445 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5446 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5447 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5450 if (rect) {
5451 glEnable(GL_SCISSOR_TEST);
5452 if(surface_is_offscreen(surface)) {
5453 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5454 } else {
5455 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5456 rect->x2 - rect->x1, rect->y2 - rect->y1);
5458 checkGLcall("glScissor");
5459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5460 } else {
5461 glDisable(GL_SCISSOR_TEST);
5463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5465 glDisable(GL_BLEND);
5466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5468 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5474 glClearColor(color[0], color[1], color[2], color[3]);
5475 glClear(GL_COLOR_BUFFER_BIT);
5476 checkGLcall("glClear");
5478 LEAVE_GL();
5480 wglFlush(); /* Flush to ensure ordering across contexts. */
5482 context_release(context);
5485 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5486 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5488 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5489 WINEDDBLTFX BltFx;
5491 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5493 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5494 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5495 return WINED3DERR_INVALIDCALL;
5498 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5499 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5500 color_fill_fbo(iface, pSurface, pRect, c);
5501 return WINED3D_OK;
5502 } else {
5503 /* Just forward this to the DirectDraw blitting engine */
5504 memset(&BltFx, 0, sizeof(BltFx));
5505 BltFx.dwSize = sizeof(BltFx);
5506 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5507 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5508 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5512 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5513 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5515 IWineD3DResource *resource;
5516 IWineD3DSurface *surface;
5517 HRESULT hr;
5519 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5520 if (FAILED(hr))
5522 ERR("Failed to get resource, hr %#x\n", hr);
5523 return;
5526 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5528 FIXME("Only supported on surface resources\n");
5529 IWineD3DResource_Release(resource);
5530 return;
5533 surface = (IWineD3DSurface *)resource;
5535 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5537 color_fill_fbo(iface, surface, NULL, color);
5539 else
5541 WINEDDBLTFX BltFx;
5542 WINED3DCOLOR c;
5544 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5546 c = ((DWORD)(color[2] * 255.0f));
5547 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5548 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5549 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5551 /* Just forward this to the DirectDraw blitting engine */
5552 memset(&BltFx, 0, sizeof(BltFx));
5553 BltFx.dwSize = sizeof(BltFx);
5554 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5555 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5556 if (FAILED(hr))
5558 ERR("Blt failed, hr %#x\n", hr);
5562 IWineD3DResource_Release(resource);
5565 /* rendertarget and depth stencil functions */
5566 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5569 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5571 ERR("(%p) : Only %d render targets are supported.\n",
5572 This, This->adapter->gl_info.limits.buffers);
5573 return WINED3DERR_INVALIDCALL;
5576 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5577 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5578 /* Note inc ref on returned surface */
5579 if(*ppRenderTarget != NULL)
5580 IWineD3DSurface_AddRef(*ppRenderTarget);
5581 return WINED3D_OK;
5584 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5585 IWineD3DSurface *front, IWineD3DSurface *back)
5587 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5588 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5589 IWineD3DSwapChainImpl *swapchain;
5590 HRESULT hr;
5592 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5594 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5596 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5597 return hr;
5600 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5602 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5603 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5604 return WINED3DERR_INVALIDCALL;
5607 if (back_impl)
5609 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5611 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5612 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5613 return WINED3DERR_INVALIDCALL;
5616 if (!swapchain->backBuffer)
5618 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5619 if (!swapchain->backBuffer)
5621 ERR("Failed to allocate back buffer array memory.\n");
5622 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5623 return E_OUTOFMEMORY;
5628 if (swapchain->frontBuffer != front)
5630 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5632 if (swapchain->frontBuffer)
5634 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5635 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5637 swapchain->frontBuffer = front;
5639 if (front)
5641 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5642 front_impl->Flags |= SFLAG_SWAPCHAIN;
5646 if (swapchain->backBuffer[0] != back)
5648 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5650 if (swapchain->backBuffer[0])
5652 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5653 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5655 swapchain->backBuffer[0] = back;
5657 if (back)
5659 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5660 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5661 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5662 swapchain->presentParms.BackBufferCount = 1;
5664 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5665 back_impl->Flags |= SFLAG_SWAPCHAIN;
5667 else
5669 swapchain->presentParms.BackBufferCount = 0;
5670 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5671 swapchain->backBuffer = NULL;
5675 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5676 return WINED3D_OK;
5679 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 *ppZStencilSurface = This->stencilBufferTarget;
5682 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5684 if(*ppZStencilSurface != NULL) {
5685 /* Note inc ref on returned surface */
5686 IWineD3DSurface_AddRef(*ppZStencilSurface);
5687 return WINED3D_OK;
5688 } else {
5689 return WINED3DERR_NOTFOUND;
5693 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const RECT *src_rect_in,
5694 IWineD3DSurface *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5697 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5698 const struct wined3d_gl_info *gl_info;
5699 struct wined3d_context *context;
5700 GLenum gl_filter;
5701 POINT offset = {0, 0};
5702 RECT src_rect, dst_rect;
5704 TRACE("(%p) : src_surface %p, src_rect_in %p, dst_surface %p, dst_rect_in %p, filter %s (0x%08x)\n",
5705 This, src_surface, src_rect_in, dst_surface, dst_rect_in, debug_d3dtexturefiltertype(filter), filter);
5706 TRACE("src_rect_in %s\n", wine_dbgstr_rect(src_rect_in));
5707 TRACE("dst_rect_in %s\n", wine_dbgstr_rect(dst_rect_in));
5709 src_rect = *src_rect_in;
5710 dst_rect = *dst_rect_in;
5712 switch (filter) {
5713 case WINED3DTEXF_LINEAR:
5714 gl_filter = GL_LINEAR;
5715 break;
5717 default:
5718 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5719 case WINED3DTEXF_NONE:
5720 case WINED3DTEXF_POINT:
5721 gl_filter = GL_NEAREST;
5722 break;
5725 /* Make sure the drawables are up-to-date. Note that loading the
5726 * destination surface isn't strictly required if we overwrite the
5727 * entire surface. */
5728 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5729 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5731 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5732 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5733 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5735 if (!context->valid)
5737 context_release(context);
5738 WARN("Invalid context, skipping blit.\n");
5739 return;
5742 gl_info = context->gl_info;
5744 if (!surface_is_offscreen(src_surface))
5746 GLenum buffer = surface_get_gl_buffer(src_surface);
5748 TRACE("Source surface %p is onscreen\n", src_surface);
5750 if(buffer == GL_FRONT) {
5751 RECT windowsize;
5752 UINT h;
5753 ClientToScreen(context->win_handle, &offset);
5754 GetClientRect(context->win_handle, &windowsize);
5755 h = windowsize.bottom - windowsize.top;
5756 src_rect.left -= offset.x; src_rect.right -=offset.x;
5757 src_rect.top = offset.y + h - src_rect.top;
5758 src_rect.bottom = offset.y + h - src_rect.bottom;
5759 } else {
5760 src_rect.top = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.top;
5761 src_rect.bottom = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.bottom;
5764 ENTER_GL();
5765 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5766 glReadBuffer(buffer);
5767 checkGLcall("glReadBuffer()");
5768 } else {
5769 TRACE("Source surface %p is offscreen\n", src_surface);
5770 ENTER_GL();
5771 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5772 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5773 glReadBuffer(GL_COLOR_ATTACHMENT0);
5774 checkGLcall("glReadBuffer()");
5775 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5777 LEAVE_GL();
5779 /* Attach dst surface to dst fbo */
5780 if (!surface_is_offscreen(dst_surface))
5782 GLenum buffer = surface_get_gl_buffer(dst_surface);
5784 TRACE("Destination surface %p is onscreen\n", dst_surface);
5786 if(buffer == GL_FRONT) {
5787 RECT windowsize;
5788 UINT h;
5789 ClientToScreen(context->win_handle, &offset);
5790 GetClientRect(context->win_handle, &windowsize);
5791 h = windowsize.bottom - windowsize.top;
5792 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5793 dst_rect.top = offset.y + h - dst_rect.top;
5794 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5795 } else {
5796 /* Screen coords = window coords, surface height = window height */
5797 dst_rect.top = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.top;
5798 dst_rect.bottom = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.bottom;
5801 ENTER_GL();
5802 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5803 context_set_draw_buffer(context, buffer);
5805 else
5807 TRACE("Destination surface %p is offscreen\n", dst_surface);
5809 ENTER_GL();
5810 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5811 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5812 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5813 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5815 glDisable(GL_SCISSOR_TEST);
5816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5818 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5819 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5820 checkGLcall("glBlitFramebuffer()");
5822 LEAVE_GL();
5824 wglFlush(); /* Flush to ensure ordering across contexts. */
5826 context_release(context);
5828 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5831 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5832 BOOL set_viewport) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5835 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5837 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5839 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5840 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5841 return WINED3DERR_INVALIDCALL;
5844 /* MSDN says that null disables the render target
5845 but a device must always be associated with a render target
5846 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5848 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5849 FIXME("Trying to set render target 0 to NULL\n");
5850 return WINED3DERR_INVALIDCALL;
5852 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5853 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);
5854 return WINED3DERR_INVALIDCALL;
5857 /* If we are trying to set what we already have, don't bother */
5858 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5859 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5860 return WINED3D_OK;
5862 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5863 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5864 This->render_targets[RenderTargetIndex] = pRenderTarget;
5866 /* Render target 0 is special */
5867 if(RenderTargetIndex == 0 && set_viewport) {
5868 /* Finally, reset the viewport and scissor rect as the MSDN states.
5869 * Tests show that stateblock recording is ignored, the change goes
5870 * directly into the primary stateblock.
5872 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5873 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5874 This->stateBlock->viewport.X = 0;
5875 This->stateBlock->viewport.Y = 0;
5876 This->stateBlock->viewport.MaxZ = 1.0f;
5877 This->stateBlock->viewport.MinZ = 0.0f;
5878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5880 This->stateBlock->scissorRect.top = 0;
5881 This->stateBlock->scissorRect.left = 0;
5882 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5883 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5886 return WINED3D_OK;
5889 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5891 HRESULT hr = WINED3D_OK;
5892 IWineD3DSurface *tmp;
5894 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5896 if (pNewZStencil == This->stencilBufferTarget) {
5897 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5898 } else {
5899 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5900 * depending on the renter target implementation being used.
5901 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5902 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5903 * stencil buffer and incur an extra memory overhead
5904 ******************************************************/
5906 if (This->stencilBufferTarget) {
5907 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5908 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5909 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5910 } else {
5911 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5912 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5913 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5914 context_release(context);
5918 tmp = This->stencilBufferTarget;
5919 This->stencilBufferTarget = pNewZStencil;
5920 /* should we be calling the parent or the wined3d surface? */
5921 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5922 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5923 hr = WINED3D_OK;
5925 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5926 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5933 return hr;
5936 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5937 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5939 /* TODO: the use of Impl is deprecated. */
5940 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5941 WINED3DLOCKED_RECT lockedRect;
5943 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5945 /* some basic validation checks */
5946 if(This->cursorTexture) {
5947 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5948 ENTER_GL();
5949 glDeleteTextures(1, &This->cursorTexture);
5950 LEAVE_GL();
5951 context_release(context);
5952 This->cursorTexture = 0;
5955 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5956 This->haveHardwareCursor = TRUE;
5957 else
5958 This->haveHardwareCursor = FALSE;
5960 if(pCursorBitmap) {
5961 WINED3DLOCKED_RECT rect;
5963 /* MSDN: Cursor must be A8R8G8B8 */
5964 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5966 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5967 return WINED3DERR_INVALIDCALL;
5970 /* MSDN: Cursor must be smaller than the display mode */
5971 if(pSur->currentDesc.Width > This->ddraw_width ||
5972 pSur->currentDesc.Height > This->ddraw_height) {
5973 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);
5974 return WINED3DERR_INVALIDCALL;
5977 if (!This->haveHardwareCursor) {
5978 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5980 /* Do not store the surface's pointer because the application may
5981 * release it after setting the cursor image. Windows doesn't
5982 * addref the set surface, so we can't do this either without
5983 * creating circular refcount dependencies. Copy out the gl texture
5984 * instead.
5986 This->cursorWidth = pSur->currentDesc.Width;
5987 This->cursorHeight = pSur->currentDesc.Height;
5988 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5990 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5991 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5992 struct wined3d_context *context;
5993 char *mem, *bits = rect.pBits;
5994 GLint intfmt = format_desc->glInternal;
5995 GLint format = format_desc->glFormat;
5996 GLint type = format_desc->glType;
5997 INT height = This->cursorHeight;
5998 INT width = This->cursorWidth;
5999 INT bpp = format_desc->byte_count;
6000 DWORD sampler;
6001 INT i;
6003 /* Reformat the texture memory (pitch and width can be
6004 * different) */
6005 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6006 for(i = 0; i < height; i++)
6007 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6008 IWineD3DSurface_UnlockRect(pCursorBitmap);
6010 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6012 ENTER_GL();
6014 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6016 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6017 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6020 /* Make sure that a proper texture unit is selected */
6021 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6022 checkGLcall("glActiveTextureARB");
6023 sampler = This->rev_tex_unit_map[0];
6024 if (sampler != WINED3D_UNMAPPED_STAGE)
6026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6028 /* Create a new cursor texture */
6029 glGenTextures(1, &This->cursorTexture);
6030 checkGLcall("glGenTextures");
6031 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6032 checkGLcall("glBindTexture");
6033 /* Copy the bitmap memory into the cursor texture */
6034 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6035 HeapFree(GetProcessHeap(), 0, mem);
6036 checkGLcall("glTexImage2D");
6038 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6040 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6041 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6044 LEAVE_GL();
6046 context_release(context);
6048 else
6050 FIXME("A cursor texture was not returned.\n");
6051 This->cursorTexture = 0;
6054 else
6056 /* Draw a hardware cursor */
6057 ICONINFO cursorInfo;
6058 HCURSOR cursor;
6059 /* Create and clear maskBits because it is not needed for
6060 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6061 * chunks. */
6062 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6063 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6064 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6065 WINED3DLOCK_NO_DIRTY_UPDATE |
6066 WINED3DLOCK_READONLY
6068 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6069 pSur->currentDesc.Height);
6071 cursorInfo.fIcon = FALSE;
6072 cursorInfo.xHotspot = XHotSpot;
6073 cursorInfo.yHotspot = YHotSpot;
6074 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6075 1, 1, maskBits);
6076 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6077 1, 32, lockedRect.pBits);
6078 IWineD3DSurface_UnlockRect(pCursorBitmap);
6079 /* Create our cursor and clean up. */
6080 cursor = CreateIconIndirect(&cursorInfo);
6081 SetCursor(cursor);
6082 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6083 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6084 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6085 This->hardwareCursor = cursor;
6086 HeapFree(GetProcessHeap(), 0, maskBits);
6090 This->xHotSpot = XHotSpot;
6091 This->yHotSpot = YHotSpot;
6092 return WINED3D_OK;
6095 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6097 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6099 This->xScreenSpace = XScreenSpace;
6100 This->yScreenSpace = YScreenSpace;
6102 return;
6106 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6108 BOOL oldVisible = This->bCursorVisible;
6109 POINT pt;
6111 TRACE("(%p) : visible(%d)\n", This, bShow);
6114 * When ShowCursor is first called it should make the cursor appear at the OS's last
6115 * known cursor position. Because of this, some applications just repetitively call
6116 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6118 GetCursorPos(&pt);
6119 This->xScreenSpace = pt.x;
6120 This->yScreenSpace = pt.y;
6122 if (This->haveHardwareCursor) {
6123 This->bCursorVisible = bShow;
6124 if (bShow)
6125 SetCursor(This->hardwareCursor);
6126 else
6127 SetCursor(NULL);
6129 else
6131 if (This->cursorTexture)
6132 This->bCursorVisible = bShow;
6135 return oldVisible;
6138 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6139 TRACE("checking resource %p for eviction\n", resource);
6140 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6141 TRACE("Evicting %p\n", resource);
6142 IWineD3DResource_UnLoad(resource);
6144 IWineD3DResource_Release(resource);
6145 return S_OK;
6148 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6150 TRACE("iface %p.\n", iface);
6152 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6153 return WINED3D_OK;
6156 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6158 IWineD3DDeviceImpl *device = surface->resource.device;
6159 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6161 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6162 if(surface->Flags & SFLAG_DIBSECTION) {
6163 /* Release the DC */
6164 SelectObject(surface->hDC, surface->dib.holdbitmap);
6165 DeleteDC(surface->hDC);
6166 /* Release the DIB section */
6167 DeleteObject(surface->dib.DIBsection);
6168 surface->dib.bitmap_data = NULL;
6169 surface->resource.allocatedMemory = NULL;
6170 surface->Flags &= ~SFLAG_DIBSECTION;
6172 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6173 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6174 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6175 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6177 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6178 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6179 } else {
6180 surface->pow2Width = surface->pow2Height = 1;
6181 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6182 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6184 surface->glRect.left = 0;
6185 surface->glRect.top = 0;
6186 surface->glRect.right = surface->pow2Width;
6187 surface->glRect.bottom = surface->pow2Height;
6189 if (surface->texture_name)
6191 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6192 ENTER_GL();
6193 glDeleteTextures(1, &surface->texture_name);
6194 LEAVE_GL();
6195 context_release(context);
6196 surface->texture_name = 0;
6197 surface->Flags &= ~SFLAG_CLIENT;
6199 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6200 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6201 surface->Flags |= SFLAG_NONPOW2;
6202 } else {
6203 surface->Flags &= ~SFLAG_NONPOW2;
6205 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6206 surface->resource.allocatedMemory = NULL;
6207 surface->resource.heapMemory = NULL;
6208 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6210 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6211 * to a FBO */
6212 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6214 return E_OUTOFMEMORY;
6216 return WINED3D_OK;
6219 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6220 TRACE("Unloading resource %p\n", resource);
6221 IWineD3DResource_UnLoad(resource);
6222 IWineD3DResource_Release(resource);
6223 return S_OK;
6226 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6228 UINT i, count;
6229 WINED3DDISPLAYMODE m;
6230 HRESULT hr;
6232 /* All Windowed modes are supported, as is leaving the current mode */
6233 if(pp->Windowed) return TRUE;
6234 if(!pp->BackBufferWidth) return TRUE;
6235 if(!pp->BackBufferHeight) return TRUE;
6237 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6238 for(i = 0; i < count; i++) {
6239 memset(&m, 0, sizeof(m));
6240 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6241 if(FAILED(hr)) {
6242 ERR("EnumAdapterModes failed\n");
6244 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6245 /* Mode found, it is supported */
6246 return TRUE;
6249 /* Mode not found -> not supported */
6250 return FALSE;
6253 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6256 const struct wined3d_gl_info *gl_info;
6257 struct wined3d_context *context;
6258 IWineD3DBaseShaderImpl *shader;
6260 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6261 gl_info = context->gl_info;
6263 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6264 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6265 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6268 ENTER_GL();
6269 if(This->depth_blt_texture) {
6270 glDeleteTextures(1, &This->depth_blt_texture);
6271 This->depth_blt_texture = 0;
6273 if (This->depth_blt_rb) {
6274 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6275 This->depth_blt_rb = 0;
6276 This->depth_blt_rb_w = 0;
6277 This->depth_blt_rb_h = 0;
6279 LEAVE_GL();
6281 This->blitter->free_private(iface);
6282 This->frag_pipe->free_private(iface);
6283 This->shader_backend->shader_free_private(iface);
6284 destroy_dummy_textures(This, gl_info);
6286 context_release(context);
6288 while (This->numContexts)
6290 context_destroy(This, This->contexts[0]);
6292 HeapFree(GetProcessHeap(), 0, swapchain->context);
6293 swapchain->context = NULL;
6294 swapchain->num_contexts = 0;
6297 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6300 struct wined3d_context *context;
6301 HRESULT hr;
6302 IWineD3DSurfaceImpl *target;
6304 /* Recreate the primary swapchain's context */
6305 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6306 if (!swapchain->context)
6308 ERR("Failed to allocate memory for swapchain context array.\n");
6309 return E_OUTOFMEMORY;
6312 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6313 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6315 WARN("Failed to create context.\n");
6316 HeapFree(GetProcessHeap(), 0, swapchain->context);
6317 return E_FAIL;
6320 swapchain->context[0] = context;
6321 swapchain->num_contexts = 1;
6322 create_dummy_textures(This);
6323 context_release(context);
6325 hr = This->shader_backend->shader_alloc_private(iface);
6326 if (FAILED(hr))
6328 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6329 goto err;
6332 hr = This->frag_pipe->alloc_private(iface);
6333 if (FAILED(hr))
6335 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6336 This->shader_backend->shader_free_private(iface);
6337 goto err;
6340 hr = This->blitter->alloc_private(iface);
6341 if (FAILED(hr))
6343 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6344 This->frag_pipe->free_private(iface);
6345 This->shader_backend->shader_free_private(iface);
6346 goto err;
6349 return WINED3D_OK;
6351 err:
6352 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6353 destroy_dummy_textures(This, context->gl_info);
6354 context_release(context);
6355 context_destroy(This, context);
6356 HeapFree(GetProcessHeap(), 0, swapchain->context);
6357 swapchain->num_contexts = 0;
6358 return hr;
6361 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6363 IWineD3DSwapChainImpl *swapchain;
6364 HRESULT hr;
6365 BOOL DisplayModeChanged = FALSE;
6366 WINED3DDISPLAYMODE mode;
6367 TRACE("(%p)\n", This);
6369 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6370 if(FAILED(hr)) {
6371 ERR("Failed to get the first implicit swapchain\n");
6372 return hr;
6375 if(!is_display_mode_supported(This, pPresentationParameters)) {
6376 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6377 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6378 pPresentationParameters->BackBufferHeight);
6379 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6380 return WINED3DERR_INVALIDCALL;
6383 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6384 * on an existing gl context, so there's no real need for recreation.
6386 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6388 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6390 TRACE("New params:\n");
6391 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6392 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6393 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6394 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6395 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6396 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6397 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6398 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6399 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6400 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6401 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6402 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6403 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6405 /* No special treatment of these parameters. Just store them */
6406 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6407 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6408 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6409 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6411 /* What to do about these? */
6412 if(pPresentationParameters->BackBufferCount != 0 &&
6413 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6414 ERR("Cannot change the back buffer count yet\n");
6416 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6417 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6418 ERR("Cannot change the back buffer format yet\n");
6420 if(pPresentationParameters->hDeviceWindow != NULL &&
6421 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6422 ERR("Cannot change the device window yet\n");
6424 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6425 HRESULT hrc;
6427 TRACE("Creating the depth stencil buffer\n");
6429 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6430 This->parent,
6431 pPresentationParameters->BackBufferWidth,
6432 pPresentationParameters->BackBufferHeight,
6433 pPresentationParameters->AutoDepthStencilFormat,
6434 pPresentationParameters->MultiSampleType,
6435 pPresentationParameters->MultiSampleQuality,
6436 FALSE,
6437 &This->auto_depth_stencil_buffer);
6439 if (FAILED(hrc)) {
6440 ERR("Failed to create the depth stencil buffer\n");
6441 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6442 return WINED3DERR_INVALIDCALL;
6446 /* Reset the depth stencil */
6447 if (pPresentationParameters->EnableAutoDepthStencil)
6448 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6449 else
6450 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6452 TRACE("Resetting stateblock\n");
6453 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6454 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6456 delete_opengl_contexts(iface, swapchain);
6458 if(pPresentationParameters->Windowed) {
6459 mode.Width = swapchain->orig_width;
6460 mode.Height = swapchain->orig_height;
6461 mode.RefreshRate = 0;
6462 mode.Format = swapchain->presentParms.BackBufferFormat;
6463 } else {
6464 mode.Width = pPresentationParameters->BackBufferWidth;
6465 mode.Height = pPresentationParameters->BackBufferHeight;
6466 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6467 mode.Format = swapchain->presentParms.BackBufferFormat;
6470 /* Should Width == 800 && Height == 0 set 800x600? */
6471 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6472 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6473 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6475 UINT i;
6477 if(!pPresentationParameters->Windowed) {
6478 DisplayModeChanged = TRUE;
6480 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6481 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6483 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6484 if(FAILED(hr))
6486 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6487 return hr;
6490 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6491 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6492 if(FAILED(hr))
6494 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6495 return hr;
6498 if(This->auto_depth_stencil_buffer) {
6499 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6500 if(FAILED(hr))
6502 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6503 return hr;
6508 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6509 || DisplayModeChanged)
6511 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6513 if (!pPresentationParameters->Windowed)
6515 if(swapchain->presentParms.Windowed) {
6516 /* switch from windowed to fs */
6517 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6518 pPresentationParameters->BackBufferHeight);
6519 } else {
6520 /* Fullscreen -> fullscreen mode change */
6521 MoveWindow(swapchain->device_window, 0, 0,
6522 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6523 TRUE);
6526 else if (!swapchain->presentParms.Windowed)
6528 /* Fullscreen -> windowed switch */
6529 swapchain_restore_fullscreen_window(swapchain);
6531 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6532 } else if(!pPresentationParameters->Windowed) {
6533 DWORD style = This->style, exStyle = This->exStyle;
6534 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6535 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6536 * Reset to clear up their mess. Guild Wars also loses the device during that.
6538 This->style = 0;
6539 This->exStyle = 0;
6540 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6541 pPresentationParameters->BackBufferHeight);
6542 This->style = style;
6543 This->exStyle = exStyle;
6546 /* Note: No parent needed for initial internal stateblock */
6547 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6548 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6549 else TRACE("Created stateblock %p\n", This->stateBlock);
6550 This->updateStateBlock = This->stateBlock;
6551 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6553 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6554 if(FAILED(hr)) {
6555 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6558 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6560 RECT client_rect;
6561 GetClientRect(swapchain->win_handle, &client_rect);
6563 if(!swapchain->presentParms.BackBufferCount)
6565 TRACE("Single buffered rendering\n");
6566 swapchain->render_to_fbo = FALSE;
6568 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6569 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6571 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6572 swapchain->presentParms.BackBufferWidth,
6573 swapchain->presentParms.BackBufferHeight,
6574 client_rect.right, client_rect.bottom);
6575 swapchain->render_to_fbo = TRUE;
6577 else
6579 TRACE("Rendering directly to GL_BACK\n");
6580 swapchain->render_to_fbo = FALSE;
6584 hr = create_primary_opengl_context(iface, swapchain);
6585 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6587 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6588 * first use
6590 return hr;
6593 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6595 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6597 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6599 return WINED3D_OK;
6603 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6605 TRACE("(%p) : pParameters %p\n", This, pParameters);
6607 *pParameters = This->createParms;
6608 return WINED3D_OK;
6611 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6612 IWineD3DSwapChain *swapchain;
6614 TRACE("Relaying to swapchain\n");
6616 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6617 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6618 IWineD3DSwapChain_Release(swapchain);
6622 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6623 IWineD3DSwapChain *swapchain;
6625 TRACE("Relaying to swapchain\n");
6627 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6628 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6629 IWineD3DSwapChain_Release(swapchain);
6634 /** ********************************************************
6635 * Notification functions
6636 ** ********************************************************/
6637 /** This function must be called in the release of a resource when ref == 0,
6638 * the contents of resource must still be correct,
6639 * any handles to other resource held by the caller must be closed
6640 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6641 *****************************************************/
6642 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6644 TRACE("(%p) : Adding resource %p\n", This, resource);
6646 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6649 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6651 TRACE("(%p) : Removing resource %p\n", This, resource);
6653 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6656 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6658 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6659 int counter;
6661 TRACE("(%p) : resource %p\n", This, resource);
6663 context_resource_released((IWineD3DDevice *)This, resource, type);
6665 switch (type) {
6666 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6667 case WINED3DRTYPE_SURFACE: {
6668 unsigned int i;
6670 if (This->d3d_initialized)
6672 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6674 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6675 This->render_targets[i] = NULL;
6678 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6679 This->stencilBufferTarget = NULL;
6683 break;
6685 case WINED3DRTYPE_TEXTURE:
6686 case WINED3DRTYPE_CUBETEXTURE:
6687 case WINED3DRTYPE_VOLUMETEXTURE:
6688 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6689 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6690 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6691 This->stateBlock->textures[counter] = NULL;
6693 if (This->updateStateBlock != This->stateBlock ){
6694 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6695 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6696 This->updateStateBlock->textures[counter] = NULL;
6700 break;
6701 case WINED3DRTYPE_VOLUME:
6702 /* TODO: nothing really? */
6703 break;
6704 case WINED3DRTYPE_BUFFER:
6706 int streamNumber;
6707 TRACE("Cleaning up stream pointers\n");
6709 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6710 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6711 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6713 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6714 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6715 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6716 This->updateStateBlock->streamSource[streamNumber] = 0;
6717 /* Set changed flag? */
6720 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) */
6721 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6722 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6723 This->stateBlock->streamSource[streamNumber] = 0;
6728 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6729 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6730 This->updateStateBlock->pIndexData = NULL;
6733 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6734 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6735 This->stateBlock->pIndexData = NULL;
6739 break;
6741 default:
6742 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6743 break;
6747 /* Remove the resource from the resourceStore */
6748 device_resource_remove(This, resource);
6750 TRACE("Resource released\n");
6754 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6756 IWineD3DResourceImpl *resource, *cursor;
6757 HRESULT ret;
6758 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6760 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6761 TRACE("enumerating resource %p\n", resource);
6762 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6763 ret = pCallback((IWineD3DResource *) resource, pData);
6764 if(ret == S_FALSE) {
6765 TRACE("Canceling enumeration\n");
6766 break;
6769 return WINED3D_OK;
6772 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6775 IWineD3DResourceImpl *resource;
6777 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6779 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6780 if (type == WINED3DRTYPE_SURFACE)
6782 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6784 TRACE("Found surface %p for dc %p.\n", resource, dc);
6785 *surface = (IWineD3DSurface *)resource;
6786 return WINED3D_OK;
6791 return WINED3DERR_INVALIDCALL;
6794 /**********************************************************
6795 * IWineD3DDevice VTbl follows
6796 **********************************************************/
6798 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6800 /*** IUnknown methods ***/
6801 IWineD3DDeviceImpl_QueryInterface,
6802 IWineD3DDeviceImpl_AddRef,
6803 IWineD3DDeviceImpl_Release,
6804 /*** IWineD3DDevice methods ***/
6805 IWineD3DDeviceImpl_GetParent,
6806 /*** Creation methods**/
6807 IWineD3DDeviceImpl_CreateBuffer,
6808 IWineD3DDeviceImpl_CreateVertexBuffer,
6809 IWineD3DDeviceImpl_CreateIndexBuffer,
6810 IWineD3DDeviceImpl_CreateStateBlock,
6811 IWineD3DDeviceImpl_CreateSurface,
6812 IWineD3DDeviceImpl_CreateRendertargetView,
6813 IWineD3DDeviceImpl_CreateTexture,
6814 IWineD3DDeviceImpl_CreateVolumeTexture,
6815 IWineD3DDeviceImpl_CreateVolume,
6816 IWineD3DDeviceImpl_CreateCubeTexture,
6817 IWineD3DDeviceImpl_CreateQuery,
6818 IWineD3DDeviceImpl_CreateSwapChain,
6819 IWineD3DDeviceImpl_CreateVertexDeclaration,
6820 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6821 IWineD3DDeviceImpl_CreateVertexShader,
6822 IWineD3DDeviceImpl_CreateGeometryShader,
6823 IWineD3DDeviceImpl_CreatePixelShader,
6824 IWineD3DDeviceImpl_CreatePalette,
6825 /*** Odd functions **/
6826 IWineD3DDeviceImpl_Init3D,
6827 IWineD3DDeviceImpl_InitGDI,
6828 IWineD3DDeviceImpl_Uninit3D,
6829 IWineD3DDeviceImpl_UninitGDI,
6830 IWineD3DDeviceImpl_SetMultithreaded,
6831 IWineD3DDeviceImpl_EvictManagedResources,
6832 IWineD3DDeviceImpl_GetAvailableTextureMem,
6833 IWineD3DDeviceImpl_GetBackBuffer,
6834 IWineD3DDeviceImpl_GetCreationParameters,
6835 IWineD3DDeviceImpl_GetDeviceCaps,
6836 IWineD3DDeviceImpl_GetDirect3D,
6837 IWineD3DDeviceImpl_GetDisplayMode,
6838 IWineD3DDeviceImpl_SetDisplayMode,
6839 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6840 IWineD3DDeviceImpl_GetRasterStatus,
6841 IWineD3DDeviceImpl_GetSwapChain,
6842 IWineD3DDeviceImpl_Reset,
6843 IWineD3DDeviceImpl_SetDialogBoxMode,
6844 IWineD3DDeviceImpl_SetCursorProperties,
6845 IWineD3DDeviceImpl_SetCursorPosition,
6846 IWineD3DDeviceImpl_ShowCursor,
6847 /*** Getters and setters **/
6848 IWineD3DDeviceImpl_SetClipPlane,
6849 IWineD3DDeviceImpl_GetClipPlane,
6850 IWineD3DDeviceImpl_SetClipStatus,
6851 IWineD3DDeviceImpl_GetClipStatus,
6852 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6853 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6854 IWineD3DDeviceImpl_SetDepthStencilSurface,
6855 IWineD3DDeviceImpl_GetDepthStencilSurface,
6856 IWineD3DDeviceImpl_SetGammaRamp,
6857 IWineD3DDeviceImpl_GetGammaRamp,
6858 IWineD3DDeviceImpl_SetIndexBuffer,
6859 IWineD3DDeviceImpl_GetIndexBuffer,
6860 IWineD3DDeviceImpl_SetBaseVertexIndex,
6861 IWineD3DDeviceImpl_GetBaseVertexIndex,
6862 IWineD3DDeviceImpl_SetLight,
6863 IWineD3DDeviceImpl_GetLight,
6864 IWineD3DDeviceImpl_SetLightEnable,
6865 IWineD3DDeviceImpl_GetLightEnable,
6866 IWineD3DDeviceImpl_SetMaterial,
6867 IWineD3DDeviceImpl_GetMaterial,
6868 IWineD3DDeviceImpl_SetNPatchMode,
6869 IWineD3DDeviceImpl_GetNPatchMode,
6870 IWineD3DDeviceImpl_SetPaletteEntries,
6871 IWineD3DDeviceImpl_GetPaletteEntries,
6872 IWineD3DDeviceImpl_SetPixelShader,
6873 IWineD3DDeviceImpl_GetPixelShader,
6874 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6875 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6876 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6877 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6878 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6879 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6880 IWineD3DDeviceImpl_SetRenderState,
6881 IWineD3DDeviceImpl_GetRenderState,
6882 IWineD3DDeviceImpl_SetRenderTarget,
6883 IWineD3DDeviceImpl_GetRenderTarget,
6884 IWineD3DDeviceImpl_SetFrontBackBuffers,
6885 IWineD3DDeviceImpl_SetSamplerState,
6886 IWineD3DDeviceImpl_GetSamplerState,
6887 IWineD3DDeviceImpl_SetScissorRect,
6888 IWineD3DDeviceImpl_GetScissorRect,
6889 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6890 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6891 IWineD3DDeviceImpl_SetStreamSource,
6892 IWineD3DDeviceImpl_GetStreamSource,
6893 IWineD3DDeviceImpl_SetStreamSourceFreq,
6894 IWineD3DDeviceImpl_GetStreamSourceFreq,
6895 IWineD3DDeviceImpl_SetTexture,
6896 IWineD3DDeviceImpl_GetTexture,
6897 IWineD3DDeviceImpl_SetTextureStageState,
6898 IWineD3DDeviceImpl_GetTextureStageState,
6899 IWineD3DDeviceImpl_SetTransform,
6900 IWineD3DDeviceImpl_GetTransform,
6901 IWineD3DDeviceImpl_SetVertexDeclaration,
6902 IWineD3DDeviceImpl_GetVertexDeclaration,
6903 IWineD3DDeviceImpl_SetVertexShader,
6904 IWineD3DDeviceImpl_GetVertexShader,
6905 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6906 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6907 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6908 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6909 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6910 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6911 IWineD3DDeviceImpl_SetViewport,
6912 IWineD3DDeviceImpl_GetViewport,
6913 IWineD3DDeviceImpl_MultiplyTransform,
6914 IWineD3DDeviceImpl_ValidateDevice,
6915 IWineD3DDeviceImpl_ProcessVertices,
6916 /*** State block ***/
6917 IWineD3DDeviceImpl_BeginStateBlock,
6918 IWineD3DDeviceImpl_EndStateBlock,
6919 /*** Scene management ***/
6920 IWineD3DDeviceImpl_BeginScene,
6921 IWineD3DDeviceImpl_EndScene,
6922 IWineD3DDeviceImpl_Present,
6923 IWineD3DDeviceImpl_Clear,
6924 IWineD3DDeviceImpl_ClearRendertargetView,
6925 /*** Drawing ***/
6926 IWineD3DDeviceImpl_SetPrimitiveType,
6927 IWineD3DDeviceImpl_GetPrimitiveType,
6928 IWineD3DDeviceImpl_DrawPrimitive,
6929 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6930 IWineD3DDeviceImpl_DrawPrimitiveUP,
6931 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6932 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6933 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6934 IWineD3DDeviceImpl_DrawRectPatch,
6935 IWineD3DDeviceImpl_DrawTriPatch,
6936 IWineD3DDeviceImpl_DeletePatch,
6937 IWineD3DDeviceImpl_ColorFill,
6938 IWineD3DDeviceImpl_UpdateTexture,
6939 IWineD3DDeviceImpl_UpdateSurface,
6940 IWineD3DDeviceImpl_GetFrontBufferData,
6941 /*** object tracking ***/
6942 IWineD3DDeviceImpl_EnumResources,
6943 IWineD3DDeviceImpl_GetSurfaceFromDC,
6944 IWineD3DDeviceImpl_AcquireFocusWindow,
6945 IWineD3DDeviceImpl_ReleaseFocusWindow,
6948 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6949 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6950 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6952 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6953 const struct fragment_pipeline *fragment_pipeline;
6954 struct shader_caps shader_caps;
6955 struct fragment_caps ffp_caps;
6956 WINED3DDISPLAYMODE mode;
6957 unsigned int i;
6958 HRESULT hr;
6960 device->lpVtbl = &IWineD3DDevice_Vtbl;
6961 device->ref = 1;
6962 device->wined3d = (IWineD3D *)wined3d;
6963 IWineD3D_AddRef(device->wined3d);
6964 device->adapter = wined3d->adapter_count ? adapter : NULL;
6965 device->parent = parent;
6966 device->device_parent = device_parent;
6967 list_init(&device->resources);
6968 list_init(&device->shaders);
6970 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6971 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6973 /* Get the initial screen setup for ddraw. */
6974 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6975 if (FAILED(hr))
6977 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6978 IWineD3D_Release(device->wined3d);
6979 return hr;
6981 device->ddraw_width = mode.Width;
6982 device->ddraw_height = mode.Height;
6983 device->ddraw_format = mode.Format;
6985 /* Save the creation parameters. */
6986 device->createParms.AdapterOrdinal = adapter_idx;
6987 device->createParms.DeviceType = device_type;
6988 device->createParms.hFocusWindow = focus_window;
6989 device->createParms.BehaviorFlags = flags;
6991 device->devType = device_type;
6992 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6994 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6995 device->shader_backend = adapter->shader_backend;
6997 memset(&shader_caps, 0, sizeof(shader_caps));
6998 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6999 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7000 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7001 device->vs_clipping = shader_caps.VSClipping;
7003 memset(&ffp_caps, 0, sizeof(ffp_caps));
7004 fragment_pipeline = adapter->fragment_pipe;
7005 device->frag_pipe = fragment_pipeline;
7006 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7007 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7009 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7010 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7011 if (FAILED(hr))
7013 ERR("Failed to compile state table, hr %#x.\n", hr);
7014 IWineD3D_Release(device->wined3d);
7015 return hr;
7018 device->blitter = adapter->blitter;
7020 return WINED3D_OK;
7024 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7025 DWORD rep = This->StateTable[state].representative;
7026 struct wined3d_context *context;
7027 DWORD idx;
7028 BYTE shift;
7029 UINT i;
7031 for(i = 0; i < This->numContexts; i++) {
7032 context = This->contexts[i];
7033 if(isStateDirty(context, rep)) continue;
7035 context->dirtyArray[context->numDirtyEntries++] = rep;
7036 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7037 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7038 context->isStateDirty[idx] |= (1 << shift);
7042 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7044 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7045 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7046 *width = surface->pow2Width;
7047 *height = surface->pow2Height;
7050 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7052 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7053 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7054 * current context's drawable, which is the size of the back buffer of the swapchain
7055 * the active context belongs to. */
7056 *width = swapchain->presentParms.BackBufferWidth;
7057 *height = swapchain->presentParms.BackBufferHeight;
7060 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7061 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7063 if (device->filter_messages)
7065 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7066 window, message, wparam, lparam);
7067 return DefWindowProcW(window, message, wparam, lparam);
7070 if (message == WM_DESTROY)
7072 TRACE("unregister window %p.\n", window);
7073 wined3d_unregister_window(window);
7075 if (device->focus_window == window) device->focus_window = NULL;
7076 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7079 return CallWindowProcW(proc, window, message, wparam, lparam);