shell32: Add printers CLSID to test, clean up a bit.
[wine/testsucceed.git] / dlls / wined3d / device.c
blob5ae2b5c03fbac5c036843183061feab063c6e662
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], &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 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
842 iface, resource, parent, rendertarget_view);
844 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
845 if (!object)
847 ERR("Failed to allocate memory\n");
848 return E_OUTOFMEMORY;
851 wined3d_rendertarget_view_init(object, resource, parent);
853 TRACE("Created render target view %p.\n", object);
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 struct wined3d_fvf_convert_state
1113 const struct wined3d_gl_info *gl_info;
1114 WINED3DVERTEXELEMENT *elements;
1115 UINT offset;
1116 UINT idx;
1119 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1120 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1122 WINED3DVERTEXELEMENT *elements = state->elements;
1123 const struct wined3d_format_desc *format_desc;
1124 UINT offset = state->offset;
1125 UINT idx = state->idx;
1127 elements[idx].format = format;
1128 elements[idx].input_slot = 0;
1129 elements[idx].offset = offset;
1130 elements[idx].output_slot = 0;
1131 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1132 elements[idx].usage = usage;
1133 elements[idx].usage_idx = usage_idx;
1135 format_desc = getFormatDescEntry(format, state->gl_info);
1136 state->offset += format_desc->component_count * format_desc->component_size;
1137 ++state->idx;
1140 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1141 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1143 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1144 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1145 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1146 BOOL has_blend_idx = has_blend &&
1147 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1148 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1149 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1150 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1151 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1152 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1153 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1155 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1156 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1157 struct wined3d_fvf_convert_state state;
1158 unsigned int size;
1159 unsigned int idx;
1160 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1161 if (has_blend_idx) num_blends--;
1163 /* Compute declaration size */
1164 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1165 has_psize + has_diffuse + has_specular + num_textures;
1167 state.gl_info = gl_info;
1168 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1169 if (!state.elements) return ~0U;
1170 state.offset = 0;
1171 state.idx = 0;
1173 if (has_pos)
1175 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1176 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1177 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1178 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1179 else
1180 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1183 if (has_blend && (num_blends > 0))
1185 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1186 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1187 else
1189 switch (num_blends)
1191 case 1:
1192 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1193 break;
1194 case 2:
1195 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1196 break;
1197 case 3:
1198 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1199 break;
1200 case 4:
1201 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1202 break;
1203 default:
1204 ERR("Unexpected amount of blend values: %u\n", num_blends);
1209 if (has_blend_idx)
1211 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1212 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1213 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1214 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1215 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1216 else
1217 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1220 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1221 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1222 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1223 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1225 for (idx = 0; idx < num_textures; ++idx)
1227 switch ((texcoords >> (idx * 2)) & 0x03)
1229 case WINED3DFVF_TEXTUREFORMAT1:
1230 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1231 break;
1232 case WINED3DFVF_TEXTUREFORMAT2:
1233 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1234 break;
1235 case WINED3DFVF_TEXTUREFORMAT3:
1236 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1237 break;
1238 case WINED3DFVF_TEXTUREFORMAT4:
1239 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1240 break;
1244 *ppVertexElements = state.elements;
1245 return size;
1248 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1249 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1250 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1253 WINED3DVERTEXELEMENT *elements;
1254 unsigned int size;
1255 DWORD hr;
1257 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1259 size = ConvertFvfToDeclaration(This, fvf, &elements);
1260 if (size == ~0U) return E_OUTOFMEMORY;
1262 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1263 HeapFree(GetProcessHeap(), 0, elements);
1264 return hr;
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1268 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1269 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1270 const struct wined3d_parent_ops *parent_ops)
1272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 IWineD3DVertexShaderImpl *object;
1274 HRESULT hr;
1276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1277 if (!object)
1279 ERR("Failed to allocate shader memory.\n");
1280 return E_OUTOFMEMORY;
1283 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1284 if (FAILED(hr))
1286 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1287 HeapFree(GetProcessHeap(), 0, object);
1288 return hr;
1291 TRACE("Created vertex shader %p.\n", object);
1292 *ppVertexShader = (IWineD3DVertexShader *)object;
1294 return WINED3D_OK;
1297 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1298 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1299 IWineD3DGeometryShader **shader, IUnknown *parent,
1300 const struct wined3d_parent_ops *parent_ops)
1302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1303 struct wined3d_geometryshader *object;
1304 HRESULT hr;
1306 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1307 if (!object)
1309 ERR("Failed to allocate shader memory.\n");
1310 return E_OUTOFMEMORY;
1313 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1314 if (FAILED(hr))
1316 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1317 HeapFree(GetProcessHeap(), 0, object);
1318 return hr;
1321 TRACE("Created geometry shader %p.\n", object);
1322 *shader = (IWineD3DGeometryShader *)object;
1324 return WINED3D_OK;
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1328 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1329 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1330 const struct wined3d_parent_ops *parent_ops)
1332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1333 IWineD3DPixelShaderImpl *object;
1334 HRESULT hr;
1336 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1337 if (!object)
1339 ERR("Failed to allocate shader memory.\n");
1340 return E_OUTOFMEMORY;
1343 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1344 if (FAILED(hr))
1346 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1347 HeapFree(GetProcessHeap(), 0, object);
1348 return hr;
1351 TRACE("Created pixel shader %p.\n", object);
1352 *ppPixelShader = (IWineD3DPixelShader *)object;
1354 return WINED3D_OK;
1357 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1358 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1361 IWineD3DPaletteImpl *object;
1362 HRESULT hr;
1364 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1365 iface, Flags, PalEnt, Palette, Parent);
1367 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1368 if (!object)
1370 ERR("Failed to allocate palette memory.\n");
1371 return E_OUTOFMEMORY;
1374 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1375 if (FAILED(hr))
1377 WARN("Failed to initialize palette, hr %#x.\n", hr);
1378 HeapFree(GetProcessHeap(), 0, object);
1379 return hr;
1382 TRACE("Created palette %p.\n", object);
1383 *Palette = (IWineD3DPalette *)object;
1385 return WINED3D_OK;
1388 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1389 HBITMAP hbm;
1390 BITMAP bm;
1391 HRESULT hr;
1392 HDC dcb = NULL, dcs = NULL;
1393 WINEDDCOLORKEY colorkey;
1395 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1396 if(hbm)
1398 GetObjectA(hbm, sizeof(BITMAP), &bm);
1399 dcb = CreateCompatibleDC(NULL);
1400 if(!dcb) goto out;
1401 SelectObject(dcb, hbm);
1403 else
1405 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1406 * couldn't be loaded
1408 memset(&bm, 0, sizeof(bm));
1409 bm.bmWidth = 32;
1410 bm.bmHeight = 32;
1413 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1414 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1415 NULL, &wined3d_null_parent_ops);
1416 if(FAILED(hr)) {
1417 ERR("Wine logo requested, but failed to create surface\n");
1418 goto out;
1421 if(dcb) {
1422 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1423 if(FAILED(hr)) goto out;
1424 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1425 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1427 colorkey.dwColorSpaceLowValue = 0;
1428 colorkey.dwColorSpaceHighValue = 0;
1429 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1430 } else {
1431 /* Fill the surface with a white color to show that wined3d is there */
1432 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1435 out:
1436 if (dcb) DeleteDC(dcb);
1437 if (hbm) DeleteObject(hbm);
1440 /* Context activation is done by the caller. */
1441 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1443 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1444 unsigned int i;
1445 /* Under DirectX you can have texture stage operations even if no texture is
1446 bound, whereas opengl will only do texture operations when a valid texture is
1447 bound. We emulate this by creating dummy textures and binding them to each
1448 texture stage, but disable all stages by default. Hence if a stage is enabled
1449 then the default texture will kick in until replaced by a SetTexture call */
1450 ENTER_GL();
1452 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1454 /* The dummy texture does not have client storage backing */
1455 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1456 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1459 for (i = 0; i < gl_info->limits.textures; ++i)
1461 GLubyte white = 255;
1463 /* Make appropriate texture active */
1464 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1465 checkGLcall("glActiveTextureARB");
1467 /* Generate an opengl texture name */
1468 glGenTextures(1, &This->dummyTextureName[i]);
1469 checkGLcall("glGenTextures");
1470 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1472 /* Generate a dummy 2d texture (not using 1d because they cause many
1473 * DRI drivers fall back to sw) */
1474 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1475 checkGLcall("glBindTexture");
1477 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1478 checkGLcall("glTexImage2D");
1481 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1483 /* Reenable because if supported it is enabled by default */
1484 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1485 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1488 LEAVE_GL();
1491 /* Context activation is done by the caller. */
1492 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1494 ENTER_GL();
1495 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1496 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1497 LEAVE_GL();
1499 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1502 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1504 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1506 if (!wined3d_register_window(window, device))
1508 ERR("Failed to register window %p.\n", window);
1509 return E_FAIL;
1512 device->focus_window = window;
1513 SetForegroundWindow(window);
1515 return WINED3D_OK;
1518 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1520 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1522 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1523 device->focus_window = NULL;
1526 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1527 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1530 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1531 IWineD3DSwapChainImpl *swapchain = NULL;
1532 struct wined3d_context *context;
1533 HRESULT hr;
1534 DWORD state;
1535 unsigned int i;
1537 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1539 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1540 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1542 TRACE("(%p) : Creating stateblock\n", This);
1543 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1544 hr = IWineD3DDevice_CreateStateBlock(iface,
1545 WINED3DSBT_INIT,
1546 (IWineD3DStateBlock **)&This->stateBlock,
1547 NULL);
1548 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1549 WARN("Failed to create stateblock\n");
1550 goto err_out;
1552 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1553 This->updateStateBlock = This->stateBlock;
1554 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1556 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1557 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1558 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1559 sizeof(GLenum) * gl_info->limits.buffers);
1561 This->NumberOfPalettes = 1;
1562 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1563 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1564 ERR("Out of memory!\n");
1565 hr = E_OUTOFMEMORY;
1566 goto err_out;
1568 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1569 if(!This->palettes[0]) {
1570 ERR("Out of memory!\n");
1571 hr = E_OUTOFMEMORY;
1572 goto err_out;
1574 for (i = 0; i < 256; ++i) {
1575 This->palettes[0][i].peRed = 0xFF;
1576 This->palettes[0][i].peGreen = 0xFF;
1577 This->palettes[0][i].peBlue = 0xFF;
1578 This->palettes[0][i].peFlags = 0xFF;
1580 This->currentPalette = 0;
1582 /* Initialize the texture unit mapping to a 1:1 mapping */
1583 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1585 if (state < gl_info->limits.fragment_samplers)
1587 This->texUnitMap[state] = state;
1588 This->rev_tex_unit_map[state] = state;
1589 } else {
1590 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1591 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1595 /* Setup the implicit swapchain. This also initializes a context. */
1596 TRACE("Creating implicit swapchain\n");
1597 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1598 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1599 if (FAILED(hr))
1601 WARN("Failed to create implicit swapchain\n");
1602 goto err_out;
1605 This->NumberOfSwapChains = 1;
1606 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1607 if(!This->swapchains) {
1608 ERR("Out of memory!\n");
1609 goto err_out;
1611 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1613 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1614 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1615 This->render_targets[0] = swapchain->backBuffer[0];
1617 else {
1618 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1619 This->render_targets[0] = swapchain->frontBuffer;
1621 IWineD3DSurface_AddRef(This->render_targets[0]);
1623 /* Depth Stencil support */
1624 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1625 if (NULL != This->stencilBufferTarget) {
1626 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1629 hr = This->shader_backend->shader_alloc_private(iface);
1630 if(FAILED(hr)) {
1631 TRACE("Shader private data couldn't be allocated\n");
1632 goto err_out;
1634 hr = This->frag_pipe->alloc_private(iface);
1635 if(FAILED(hr)) {
1636 TRACE("Fragment pipeline private data couldn't be allocated\n");
1637 goto err_out;
1639 hr = This->blitter->alloc_private(iface);
1640 if(FAILED(hr)) {
1641 TRACE("Blitter private data couldn't be allocated\n");
1642 goto err_out;
1645 /* Set up some starting GL setup */
1647 /* Setup all the devices defaults */
1648 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1650 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1652 create_dummy_textures(This);
1654 ENTER_GL();
1656 /* Initialize the current view state */
1657 This->view_ident = 1;
1658 This->contexts[0]->last_was_rhw = 0;
1659 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1660 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1662 switch(wined3d_settings.offscreen_rendering_mode) {
1663 case ORM_FBO:
1664 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1665 break;
1667 case ORM_BACKBUFFER:
1669 if (context_get_current()->aux_buffers > 0)
1671 TRACE("Using auxilliary buffer for offscreen rendering\n");
1672 This->offscreenBuffer = GL_AUX0;
1673 } else {
1674 TRACE("Using back buffer for offscreen rendering\n");
1675 This->offscreenBuffer = GL_BACK;
1680 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1681 LEAVE_GL();
1683 context_release(context);
1685 /* Clear the screen */
1686 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1687 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1688 0x00, 1.0f, 0);
1690 This->d3d_initialized = TRUE;
1692 if(wined3d_settings.logo) {
1693 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1695 This->highest_dirty_ps_const = 0;
1696 This->highest_dirty_vs_const = 0;
1697 return WINED3D_OK;
1699 err_out:
1700 HeapFree(GetProcessHeap(), 0, This->render_targets);
1701 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1702 HeapFree(GetProcessHeap(), 0, This->swapchains);
1703 This->NumberOfSwapChains = 0;
1704 if(This->palettes) {
1705 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1706 HeapFree(GetProcessHeap(), 0, This->palettes);
1708 This->NumberOfPalettes = 0;
1709 if(swapchain) {
1710 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1712 if(This->stateBlock) {
1713 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1714 This->stateBlock = NULL;
1716 if (This->blit_priv) {
1717 This->blitter->free_private(iface);
1719 if (This->fragment_priv) {
1720 This->frag_pipe->free_private(iface);
1722 if (This->shader_priv) {
1723 This->shader_backend->shader_free_private(iface);
1725 return hr;
1728 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1729 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1732 IWineD3DSwapChainImpl *swapchain = NULL;
1733 HRESULT hr;
1735 /* Setup the implicit swapchain */
1736 TRACE("Creating implicit swapchain\n");
1737 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1738 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1739 if (FAILED(hr))
1741 WARN("Failed to create implicit swapchain\n");
1742 goto err_out;
1745 This->NumberOfSwapChains = 1;
1746 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1747 if(!This->swapchains) {
1748 ERR("Out of memory!\n");
1749 goto err_out;
1751 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1752 return WINED3D_OK;
1754 err_out:
1755 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1756 return hr;
1759 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1761 IWineD3DResource_UnLoad(resource);
1762 IWineD3DResource_Release(resource);
1763 return WINED3D_OK;
1766 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1767 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1770 const struct wined3d_gl_info *gl_info;
1771 struct wined3d_context *context;
1772 int sampler;
1773 UINT i;
1774 TRACE("(%p)\n", This);
1776 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1778 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1779 * it was created. Thus make sure a context is active for the glDelete* calls
1781 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1782 gl_info = context->gl_info;
1784 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1786 /* Unload resources */
1787 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1789 TRACE("Deleting high order patches\n");
1790 for(i = 0; i < PATCHMAP_SIZE; i++) {
1791 struct list *e1, *e2;
1792 struct WineD3DRectPatch *patch;
1793 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1794 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1795 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1799 /* Delete the mouse cursor texture */
1800 if(This->cursorTexture) {
1801 ENTER_GL();
1802 glDeleteTextures(1, &This->cursorTexture);
1803 LEAVE_GL();
1804 This->cursorTexture = 0;
1807 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1808 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1810 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1811 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1814 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1815 * private data, it might contain opengl pointers
1817 if(This->depth_blt_texture) {
1818 ENTER_GL();
1819 glDeleteTextures(1, &This->depth_blt_texture);
1820 LEAVE_GL();
1821 This->depth_blt_texture = 0;
1823 if (This->depth_blt_rb) {
1824 ENTER_GL();
1825 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1826 LEAVE_GL();
1827 This->depth_blt_rb = 0;
1828 This->depth_blt_rb_w = 0;
1829 This->depth_blt_rb_h = 0;
1832 /* Release the update stateblock */
1833 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1834 if(This->updateStateBlock != This->stateBlock)
1835 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1837 This->updateStateBlock = NULL;
1839 { /* because were not doing proper internal refcounts releasing the primary state block
1840 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1841 to set this->stateBlock = NULL; first */
1842 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1843 This->stateBlock = NULL;
1845 /* Release the stateblock */
1846 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1847 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1851 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1852 This->blitter->free_private(iface);
1853 This->frag_pipe->free_private(iface);
1854 This->shader_backend->shader_free_private(iface);
1856 /* Release the buffers (with sanity checks)*/
1857 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1858 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1859 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1860 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1862 This->stencilBufferTarget = NULL;
1864 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1865 IWineD3DSurface_Release(This->render_targets[0]);
1867 TRACE("Setting rendertarget to NULL\n");
1868 This->render_targets[0] = NULL;
1870 if (This->auto_depth_stencil_buffer) {
1871 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1873 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1875 This->auto_depth_stencil_buffer = NULL;
1878 context_release(context);
1880 for(i=0; i < This->NumberOfSwapChains; i++) {
1881 TRACE("Releasing the implicit swapchain %d\n", i);
1882 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1883 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1887 HeapFree(GetProcessHeap(), 0, This->swapchains);
1888 This->swapchains = NULL;
1889 This->NumberOfSwapChains = 0;
1891 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1892 HeapFree(GetProcessHeap(), 0, This->palettes);
1893 This->palettes = NULL;
1894 This->NumberOfPalettes = 0;
1896 HeapFree(GetProcessHeap(), 0, This->render_targets);
1897 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1898 This->render_targets = NULL;
1899 This->draw_buffers = NULL;
1901 This->d3d_initialized = FALSE;
1903 return WINED3D_OK;
1906 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1908 unsigned int i;
1910 for(i=0; i < This->NumberOfSwapChains; i++) {
1911 TRACE("Releasing the implicit swapchain %d\n", i);
1912 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1913 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1917 HeapFree(GetProcessHeap(), 0, This->swapchains);
1918 This->swapchains = NULL;
1919 This->NumberOfSwapChains = 0;
1920 return WINED3D_OK;
1923 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1924 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1925 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1927 * There is no way to deactivate thread safety once it is enabled.
1929 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1932 /*For now just store the flag(needed in case of ddraw) */
1933 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1936 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1937 const WINED3DDISPLAYMODE* pMode) {
1938 DEVMODEW devmode;
1939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1940 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1941 LONG ret;
1942 RECT clip_rc;
1944 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1946 /* Resize the screen even without a window:
1947 * The app could have unset it with SetCooperativeLevel, but not called
1948 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1949 * but we don't have any hwnd
1952 memset(&devmode, 0, sizeof(devmode));
1953 devmode.dmSize = sizeof(devmode);
1954 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1955 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1956 devmode.dmPelsWidth = pMode->Width;
1957 devmode.dmPelsHeight = pMode->Height;
1959 devmode.dmDisplayFrequency = pMode->RefreshRate;
1960 if (pMode->RefreshRate != 0) {
1961 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1964 /* Only change the mode if necessary */
1965 if( (This->ddraw_width == pMode->Width) &&
1966 (This->ddraw_height == pMode->Height) &&
1967 (This->ddraw_format == pMode->Format) &&
1968 (pMode->RefreshRate == 0) ) {
1969 return WINED3D_OK;
1972 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1973 if (ret != DISP_CHANGE_SUCCESSFUL) {
1974 if(devmode.dmDisplayFrequency != 0) {
1975 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1976 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1977 devmode.dmDisplayFrequency = 0;
1978 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1980 if(ret != DISP_CHANGE_SUCCESSFUL) {
1981 return WINED3DERR_NOTAVAILABLE;
1985 /* Store the new values */
1986 This->ddraw_width = pMode->Width;
1987 This->ddraw_height = pMode->Height;
1988 This->ddraw_format = pMode->Format;
1990 /* And finally clip mouse to our screen */
1991 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1992 ClipCursor(&clip_rc);
1994 return WINED3D_OK;
1997 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1999 *ppD3D = This->wined3d;
2000 TRACE("Returning %p.\n", *ppD3D);
2001 IWineD3D_AddRef(*ppD3D);
2002 return WINED3D_OK;
2005 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2008 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2009 (This->adapter->TextureRam/(1024*1024)),
2010 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2011 /* return simulated texture memory left */
2012 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2015 /*****
2016 * Get / Set Stream Source
2017 *****/
2018 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2019 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2022 IWineD3DBuffer *oldSrc;
2024 if (StreamNumber >= MAX_STREAMS) {
2025 WARN("Stream out of range %d\n", StreamNumber);
2026 return WINED3DERR_INVALIDCALL;
2027 } else if(OffsetInBytes & 0x3) {
2028 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2029 return WINED3DERR_INVALIDCALL;
2032 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2033 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2035 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2037 if(oldSrc == pStreamData &&
2038 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2039 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2040 TRACE("Application is setting the old values over, nothing to do\n");
2041 return WINED3D_OK;
2044 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2045 if (pStreamData) {
2046 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2047 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2050 /* Handle recording of state blocks */
2051 if (This->isRecordingState) {
2052 TRACE("Recording... not performing anything\n");
2053 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2054 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2055 return WINED3D_OK;
2058 if (pStreamData != NULL) {
2059 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2060 IWineD3DBuffer_AddRef(pStreamData);
2062 if (oldSrc != NULL) {
2063 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2064 IWineD3DBuffer_Release(oldSrc);
2067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2069 return WINED3D_OK;
2072 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2073 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2077 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2078 This->stateBlock->streamSource[StreamNumber],
2079 This->stateBlock->streamOffset[StreamNumber],
2080 This->stateBlock->streamStride[StreamNumber]);
2082 if (StreamNumber >= MAX_STREAMS) {
2083 WARN("Stream out of range %d\n", StreamNumber);
2084 return WINED3DERR_INVALIDCALL;
2086 *pStream = This->stateBlock->streamSource[StreamNumber];
2087 *pStride = This->stateBlock->streamStride[StreamNumber];
2088 if (pOffset) {
2089 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2092 if (*pStream != NULL) {
2093 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2095 return WINED3D_OK;
2098 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2100 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2101 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2103 /* Verify input at least in d3d9 this is invalid*/
2104 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2105 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2106 return WINED3DERR_INVALIDCALL;
2108 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2109 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2110 return WINED3DERR_INVALIDCALL;
2112 if( Divider == 0 ){
2113 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2114 return WINED3DERR_INVALIDCALL;
2117 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2118 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2120 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2121 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2123 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2124 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2128 return WINED3D_OK;
2131 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2134 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2135 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2137 TRACE("(%p) : returning %d\n", This, *Divider);
2139 return WINED3D_OK;
2142 /*****
2143 * Get / Set & Multiply Transform
2144 *****/
2145 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2148 /* Most of this routine, comments included copied from ddraw tree initially: */
2149 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2151 /* Handle recording of state blocks */
2152 if (This->isRecordingState) {
2153 TRACE("Recording... not performing anything\n");
2154 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2155 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2156 return WINED3D_OK;
2160 * If the new matrix is the same as the current one,
2161 * we cut off any further processing. this seems to be a reasonable
2162 * optimization because as was noticed, some apps (warcraft3 for example)
2163 * tend towards setting the same matrix repeatedly for some reason.
2165 * From here on we assume that the new matrix is different, wherever it matters.
2167 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2168 TRACE("The app is setting the same matrix over again\n");
2169 return WINED3D_OK;
2170 } else {
2171 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2175 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2176 where ViewMat = Camera space, WorldMat = world space.
2178 In OpenGL, camera and world space is combined into GL_MODELVIEW
2179 matrix. The Projection matrix stay projection matrix.
2182 /* Capture the times we can just ignore the change for now */
2183 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2184 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2185 /* Handled by the state manager */
2188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2189 return WINED3D_OK;
2192 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2195 *pMatrix = This->stateBlock->transforms[State];
2196 return WINED3D_OK;
2199 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2200 const WINED3DMATRIX *mat = NULL;
2201 WINED3DMATRIX temp;
2203 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2204 * below means it will be recorded in a state block change, but it
2205 * works regardless where it is recorded.
2206 * If this is found to be wrong, change to StateBlock.
2208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2209 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2211 if (State <= HIGHEST_TRANSFORMSTATE)
2213 mat = &This->updateStateBlock->transforms[State];
2214 } else {
2215 FIXME("Unhandled transform state!!\n");
2218 multiply_matrix(&temp, mat, pMatrix);
2220 /* Apply change via set transform - will reapply to eg. lights this way */
2221 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2224 /*****
2225 * Get / Set Light
2226 *****/
2227 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2228 you can reference any indexes you want as long as that number max are enabled at any
2229 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2230 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2231 but when recording, just build a chain pretty much of commands to be replayed. */
2233 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2234 float rho;
2235 struct wined3d_light_info *object = NULL;
2236 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2237 struct list *e;
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2240 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2242 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2243 * the gl driver.
2245 if(!pLight) {
2246 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2247 return WINED3DERR_INVALIDCALL;
2250 switch(pLight->Type) {
2251 case WINED3DLIGHT_POINT:
2252 case WINED3DLIGHT_SPOT:
2253 case WINED3DLIGHT_PARALLELPOINT:
2254 case WINED3DLIGHT_GLSPOT:
2255 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2256 * most wanted
2258 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2260 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2261 return WINED3DERR_INVALIDCALL;
2263 break;
2265 case WINED3DLIGHT_DIRECTIONAL:
2266 /* Ignores attenuation */
2267 break;
2269 default:
2270 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2271 return WINED3DERR_INVALIDCALL;
2274 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2276 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2277 if(object->OriginalIndex == Index) break;
2278 object = NULL;
2281 if(!object) {
2282 TRACE("Adding new light\n");
2283 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2284 if(!object) {
2285 ERR("Out of memory error when allocating a light\n");
2286 return E_OUTOFMEMORY;
2288 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2289 object->glIndex = -1;
2290 object->OriginalIndex = Index;
2293 /* Initialize the object */
2294 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,
2295 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2296 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2297 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2298 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2299 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2300 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2302 /* Save away the information */
2303 object->OriginalParms = *pLight;
2305 switch (pLight->Type) {
2306 case WINED3DLIGHT_POINT:
2307 /* Position */
2308 object->lightPosn[0] = pLight->Position.x;
2309 object->lightPosn[1] = pLight->Position.y;
2310 object->lightPosn[2] = pLight->Position.z;
2311 object->lightPosn[3] = 1.0f;
2312 object->cutoff = 180.0f;
2313 /* FIXME: Range */
2314 break;
2316 case WINED3DLIGHT_DIRECTIONAL:
2317 /* Direction */
2318 object->lightPosn[0] = -pLight->Direction.x;
2319 object->lightPosn[1] = -pLight->Direction.y;
2320 object->lightPosn[2] = -pLight->Direction.z;
2321 object->lightPosn[3] = 0.0f;
2322 object->exponent = 0.0f;
2323 object->cutoff = 180.0f;
2324 break;
2326 case WINED3DLIGHT_SPOT:
2327 /* Position */
2328 object->lightPosn[0] = pLight->Position.x;
2329 object->lightPosn[1] = pLight->Position.y;
2330 object->lightPosn[2] = pLight->Position.z;
2331 object->lightPosn[3] = 1.0f;
2333 /* Direction */
2334 object->lightDirn[0] = pLight->Direction.x;
2335 object->lightDirn[1] = pLight->Direction.y;
2336 object->lightDirn[2] = pLight->Direction.z;
2337 object->lightDirn[3] = 1.0f;
2340 * opengl-ish and d3d-ish spot lights use too different models for the
2341 * light "intensity" as a function of the angle towards the main light direction,
2342 * so we only can approximate very roughly.
2343 * however spot lights are rather rarely used in games (if ever used at all).
2344 * furthermore if still used, probably nobody pays attention to such details.
2346 if (pLight->Falloff == 0) {
2347 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2348 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2349 * will always be 1.0 for both of them, and we don't have to care for the
2350 * rest of the rather complex calculation
2352 object->exponent = 0.0f;
2353 } else {
2354 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2355 if (rho < 0.0001f) rho = 0.0001f;
2356 object->exponent = -0.3f/logf(cosf(rho/2));
2358 if (object->exponent > 128.0f)
2360 object->exponent = 128.0f;
2362 object->cutoff = pLight->Phi*90/M_PI;
2364 /* FIXME: Range */
2365 break;
2367 default:
2368 FIXME("Unrecognized light type %d\n", pLight->Type);
2371 /* Update the live definitions if the light is currently assigned a glIndex */
2372 if (object->glIndex != -1 && !This->isRecordingState) {
2373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2375 return WINED3D_OK;
2378 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2380 struct wined3d_light_info *lightInfo = NULL;
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2382 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2383 struct list *e;
2384 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2386 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2388 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2389 if(lightInfo->OriginalIndex == Index) break;
2390 lightInfo = NULL;
2393 if (lightInfo == NULL) {
2394 TRACE("Light information requested but light not defined\n");
2395 return WINED3DERR_INVALIDCALL;
2398 *pLight = lightInfo->OriginalParms;
2399 return WINED3D_OK;
2402 /*****
2403 * Get / Set Light Enable
2404 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2405 *****/
2406 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2408 struct wined3d_light_info *lightInfo = NULL;
2409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2410 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2411 struct list *e;
2412 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2414 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2416 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2417 if(lightInfo->OriginalIndex == Index) break;
2418 lightInfo = NULL;
2420 TRACE("Found light: %p\n", lightInfo);
2422 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2423 if (lightInfo == NULL) {
2425 TRACE("Light enabled requested but light not defined, so defining one!\n");
2426 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2428 /* Search for it again! Should be fairly quick as near head of list */
2429 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2431 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2432 if(lightInfo->OriginalIndex == Index) break;
2433 lightInfo = NULL;
2435 if (lightInfo == NULL) {
2436 FIXME("Adding default lights has failed dismally\n");
2437 return WINED3DERR_INVALIDCALL;
2441 if(!Enable) {
2442 if(lightInfo->glIndex != -1) {
2443 if(!This->isRecordingState) {
2444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2447 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2448 lightInfo->glIndex = -1;
2449 } else {
2450 TRACE("Light already disabled, nothing to do\n");
2452 lightInfo->enabled = FALSE;
2453 } else {
2454 lightInfo->enabled = TRUE;
2455 if (lightInfo->glIndex != -1) {
2456 /* nop */
2457 TRACE("Nothing to do as light was enabled\n");
2458 } else {
2459 int i;
2460 /* Find a free gl light */
2461 for(i = 0; i < This->maxConcurrentLights; i++) {
2462 if(This->updateStateBlock->activeLights[i] == NULL) {
2463 This->updateStateBlock->activeLights[i] = lightInfo;
2464 lightInfo->glIndex = i;
2465 break;
2468 if(lightInfo->glIndex == -1) {
2469 /* Our tests show that Windows returns D3D_OK in this situation, even with
2470 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2471 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2472 * as well for those lights.
2474 * TODO: Test how this affects rendering
2476 WARN("Too many concurrently active lights\n");
2477 return WINED3D_OK;
2480 /* i == lightInfo->glIndex */
2481 if(!This->isRecordingState) {
2482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2487 return WINED3D_OK;
2490 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2492 struct wined3d_light_info *lightInfo = NULL;
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2494 struct list *e;
2495 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2496 TRACE("(%p) : for idx(%d)\n", This, Index);
2498 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2500 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2501 if(lightInfo->OriginalIndex == Index) break;
2502 lightInfo = NULL;
2505 if (lightInfo == NULL) {
2506 TRACE("Light enabled state requested but light not defined\n");
2507 return WINED3DERR_INVALIDCALL;
2509 /* true is 128 according to SetLightEnable */
2510 *pEnable = lightInfo->enabled ? 128 : 0;
2511 return WINED3D_OK;
2514 /*****
2515 * Get / Set Clip Planes
2516 *****/
2517 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2519 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2521 /* Validate Index */
2522 if (Index >= This->adapter->gl_info.limits.clipplanes)
2524 TRACE("Application has requested clipplane this device doesn't support\n");
2525 return WINED3DERR_INVALIDCALL;
2528 This->updateStateBlock->changed.clipplane |= 1 << Index;
2530 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2531 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2532 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2533 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2534 TRACE("Application is setting old values over, nothing to do\n");
2535 return WINED3D_OK;
2538 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2539 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2540 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2541 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2543 /* Handle recording of state blocks */
2544 if (This->isRecordingState) {
2545 TRACE("Recording... not performing anything\n");
2546 return WINED3D_OK;
2549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2551 return WINED3D_OK;
2554 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 TRACE("(%p) : for idx %d\n", This, Index);
2558 /* Validate Index */
2559 if (Index >= This->adapter->gl_info.limits.clipplanes)
2561 TRACE("Application has requested clipplane this device doesn't support\n");
2562 return WINED3DERR_INVALIDCALL;
2565 pPlane[0] = This->stateBlock->clipplane[Index][0];
2566 pPlane[1] = This->stateBlock->clipplane[Index][1];
2567 pPlane[2] = This->stateBlock->clipplane[Index][2];
2568 pPlane[3] = This->stateBlock->clipplane[Index][3];
2569 return WINED3D_OK;
2572 /*****
2573 * Get / Set Clip Plane Status
2574 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2575 *****/
2576 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 FIXME("(%p) : stub\n", This);
2579 if (NULL == pClipStatus) {
2580 return WINED3DERR_INVALIDCALL;
2582 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2583 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2584 return WINED3D_OK;
2587 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 FIXME("(%p) : stub\n", This);
2590 if (NULL == pClipStatus) {
2591 return WINED3DERR_INVALIDCALL;
2593 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2594 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2595 return WINED3D_OK;
2598 /*****
2599 * Get / Set Material
2600 *****/
2601 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 This->updateStateBlock->changed.material = TRUE;
2605 This->updateStateBlock->material = *pMaterial;
2607 /* Handle recording of state blocks */
2608 if (This->isRecordingState) {
2609 TRACE("Recording... not performing anything\n");
2610 return WINED3D_OK;
2613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2614 return WINED3D_OK;
2617 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2619 *pMaterial = This->updateStateBlock->material;
2620 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2621 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2622 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2623 pMaterial->Ambient.b, pMaterial->Ambient.a);
2624 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2625 pMaterial->Specular.b, pMaterial->Specular.a);
2626 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2627 pMaterial->Emissive.b, pMaterial->Emissive.a);
2628 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2630 return WINED3D_OK;
2633 /*****
2634 * Get / Set Indices
2635 *****/
2636 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2637 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 IWineD3DBuffer *oldIdxs;
2642 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2643 oldIdxs = This->updateStateBlock->pIndexData;
2645 This->updateStateBlock->changed.indices = TRUE;
2646 This->updateStateBlock->pIndexData = pIndexData;
2647 This->updateStateBlock->IndexFmt = fmt;
2649 /* Handle recording of state blocks */
2650 if (This->isRecordingState) {
2651 TRACE("Recording... not performing anything\n");
2652 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2653 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2654 return WINED3D_OK;
2657 if(oldIdxs != pIndexData) {
2658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2659 if(pIndexData) {
2660 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2661 IWineD3DBuffer_AddRef(pIndexData);
2663 if(oldIdxs) {
2664 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2665 IWineD3DBuffer_Release(oldIdxs);
2669 return WINED3D_OK;
2672 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 *ppIndexData = This->stateBlock->pIndexData;
2678 /* up ref count on ppindexdata */
2679 if (*ppIndexData) {
2680 IWineD3DBuffer_AddRef(*ppIndexData);
2681 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2682 }else{
2683 TRACE("(%p) No index data set\n", This);
2685 TRACE("Returning %p\n", *ppIndexData);
2687 return WINED3D_OK;
2690 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2691 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p)->(%d)\n", This, BaseIndex);
2695 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2696 TRACE("Application is setting the old value over, nothing to do\n");
2697 return WINED3D_OK;
2700 This->updateStateBlock->baseVertexIndex = BaseIndex;
2702 if (This->isRecordingState) {
2703 TRACE("Recording... not performing anything\n");
2704 return WINED3D_OK;
2706 /* The base vertex index affects the stream sources */
2707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2708 return WINED3D_OK;
2711 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 TRACE("(%p) : base_index %p\n", This, base_index);
2715 *base_index = This->stateBlock->baseVertexIndex;
2717 TRACE("Returning %u\n", *base_index);
2719 return WINED3D_OK;
2722 /*****
2723 * Get / Set Viewports
2724 *****/
2725 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728 TRACE("(%p)\n", This);
2729 This->updateStateBlock->changed.viewport = TRUE;
2730 This->updateStateBlock->viewport = *pViewport;
2732 /* Handle recording of state blocks */
2733 if (This->isRecordingState) {
2734 TRACE("Recording... not performing anything\n");
2735 return WINED3D_OK;
2738 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2739 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2742 return WINED3D_OK;
2746 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 TRACE("(%p)\n", This);
2749 *pViewport = This->stateBlock->viewport;
2750 return WINED3D_OK;
2753 /*****
2754 * Get / Set Render States
2755 * TODO: Verify against dx9 definitions
2756 *****/
2757 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2760 DWORD oldValue = This->stateBlock->renderState[State];
2762 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2764 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2765 This->updateStateBlock->renderState[State] = Value;
2767 /* Handle recording of state blocks */
2768 if (This->isRecordingState) {
2769 TRACE("Recording... not performing anything\n");
2770 return WINED3D_OK;
2773 /* Compared here and not before the assignment to allow proper stateblock recording */
2774 if(Value == oldValue) {
2775 TRACE("Application is setting the old value over, nothing to do\n");
2776 } else {
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2780 return WINED3D_OK;
2783 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2786 *pValue = This->stateBlock->renderState[State];
2787 return WINED3D_OK;
2790 /*****
2791 * Get / Set Sampler States
2792 * TODO: Verify against dx9 definitions
2793 *****/
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 DWORD oldValue;
2799 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2800 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2802 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2803 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2806 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2807 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2808 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2811 * SetSampler is designed to allow for more than the standard up to 8 textures
2812 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2813 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2815 * http://developer.nvidia.com/object/General_FAQ.html#t6
2817 * There are two new settings for GForce
2818 * the sampler one:
2819 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2820 * and the texture one:
2821 * GL_MAX_TEXTURE_COORDS_ARB.
2822 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2823 ******************/
2825 oldValue = This->stateBlock->samplerState[Sampler][Type];
2826 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2827 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2829 /* Handle recording of state blocks */
2830 if (This->isRecordingState) {
2831 TRACE("Recording... not performing anything\n");
2832 return WINED3D_OK;
2835 if(oldValue == Value) {
2836 TRACE("Application is setting the old value over, nothing to do\n");
2837 return WINED3D_OK;
2840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2842 return WINED3D_OK;
2845 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2848 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2849 This, Sampler, debug_d3dsamplerstate(Type), Type);
2851 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2852 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2855 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2856 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2857 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2859 *Value = This->stateBlock->samplerState[Sampler][Type];
2860 TRACE("(%p) : Returning %#x\n", This, *Value);
2862 return WINED3D_OK;
2865 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2868 This->updateStateBlock->changed.scissorRect = TRUE;
2869 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2870 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2871 return WINED3D_OK;
2873 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2875 if(This->isRecordingState) {
2876 TRACE("Recording... not performing anything\n");
2877 return WINED3D_OK;
2880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 *pRect = This->updateStateBlock->scissorRect;
2889 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2890 return WINED3D_OK;
2893 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2895 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2897 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2899 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2900 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2902 This->updateStateBlock->vertexDecl = pDecl;
2903 This->updateStateBlock->changed.vertexDecl = TRUE;
2905 if (This->isRecordingState) {
2906 TRACE("Recording... not performing anything\n");
2907 return WINED3D_OK;
2908 } else if(pDecl == oldDecl) {
2909 /* Checked after the assignment to allow proper stateblock recording */
2910 TRACE("Application is setting the old declaration over, nothing to do\n");
2911 return WINED3D_OK;
2914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2915 return WINED3D_OK;
2918 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2921 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2923 *ppDecl = This->stateBlock->vertexDecl;
2924 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2925 return WINED3D_OK;
2928 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2932 This->updateStateBlock->vertexShader = pShader;
2933 This->updateStateBlock->changed.vertexShader = TRUE;
2935 if (This->isRecordingState) {
2936 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2937 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2938 TRACE("Recording... not performing anything\n");
2939 return WINED3D_OK;
2940 } else if(oldShader == pShader) {
2941 /* Checked here to allow proper stateblock recording */
2942 TRACE("App is setting the old shader over, nothing to do\n");
2943 return WINED3D_OK;
2946 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2947 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2948 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2952 return WINED3D_OK;
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 if (NULL == ppShader) {
2959 return WINED3DERR_INVALIDCALL;
2961 *ppShader = This->stateBlock->vertexShader;
2962 if( NULL != *ppShader)
2963 IWineD3DVertexShader_AddRef(*ppShader);
2965 TRACE("(%p) : returning %p\n", This, *ppShader);
2966 return WINED3D_OK;
2969 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2970 IWineD3DDevice *iface,
2971 UINT start,
2972 CONST BOOL *srcData,
2973 UINT count) {
2975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2976 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2978 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2979 iface, srcData, start, count);
2981 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2983 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2984 for (i = 0; i < cnt; i++)
2985 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2987 for (i = start; i < cnt + start; ++i) {
2988 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2991 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2993 return WINED3D_OK;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2997 IWineD3DDevice *iface,
2998 UINT start,
2999 BOOL *dstData,
3000 UINT count) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 int cnt = min(count, MAX_CONST_B - start);
3005 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3006 iface, dstData, start, count);
3008 if (dstData == NULL || cnt < 0)
3009 return WINED3DERR_INVALIDCALL;
3011 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3012 return WINED3D_OK;
3015 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3016 IWineD3DDevice *iface,
3017 UINT start,
3018 CONST int *srcData,
3019 UINT count) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3024 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3025 iface, srcData, start, count);
3027 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3029 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3030 for (i = 0; i < cnt; i++)
3031 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3032 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3034 for (i = start; i < cnt + start; ++i) {
3035 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3038 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3040 return WINED3D_OK;
3043 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3044 IWineD3DDevice *iface,
3045 UINT start,
3046 int *dstData,
3047 UINT count) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 int cnt = min(count, MAX_CONST_I - start);
3052 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3053 iface, dstData, start, count);
3055 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3056 return WINED3DERR_INVALIDCALL;
3058 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3059 return WINED3D_OK;
3062 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3063 IWineD3DDevice *iface,
3064 UINT start,
3065 CONST float *srcData,
3066 UINT count) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 UINT i;
3071 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3072 iface, srcData, start, count);
3074 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3075 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3076 return WINED3DERR_INVALIDCALL;
3078 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3079 if(TRACE_ON(d3d)) {
3080 for (i = 0; i < count; i++)
3081 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3082 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3085 if (!This->isRecordingState)
3087 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3091 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3092 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3098 IWineD3DDevice *iface,
3099 UINT start,
3100 float *dstData,
3101 UINT count) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 int cnt = min(count, This->d3d_vshader_constantF - start);
3106 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3107 iface, dstData, start, count);
3109 if (dstData == NULL || cnt < 0)
3110 return WINED3DERR_INVALIDCALL;
3112 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3113 return WINED3D_OK;
3116 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3117 DWORD i;
3118 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3124 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3126 DWORD i = This->rev_tex_unit_map[unit];
3127 DWORD j = This->texUnitMap[stage];
3129 This->texUnitMap[stage] = unit;
3130 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3132 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3135 This->rev_tex_unit_map[unit] = stage;
3136 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3138 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3142 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3143 int i;
3145 This->fixed_function_usage_map = 0;
3146 for (i = 0; i < MAX_TEXTURES; ++i) {
3147 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3148 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3149 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3150 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3151 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3152 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3153 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3154 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3156 if (color_op == WINED3DTOP_DISABLE) {
3157 /* Not used, and disable higher stages */
3158 break;
3161 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3162 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3163 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3164 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3165 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3166 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3167 This->fixed_function_usage_map |= (1 << i);
3170 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3171 This->fixed_function_usage_map |= (1 << (i + 1));
3176 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3178 unsigned int i, tex;
3179 WORD ffu_map;
3181 device_update_fixed_function_usage_map(This);
3182 ffu_map = This->fixed_function_usage_map;
3184 if (This->max_ffp_textures == gl_info->limits.texture_stages
3185 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3187 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3189 if (!(ffu_map & 1)) continue;
3191 if (This->texUnitMap[i] != i) {
3192 device_map_stage(This, i, i);
3193 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3194 markTextureStagesDirty(This, i);
3197 return;
3200 /* Now work out the mapping */
3201 tex = 0;
3202 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3204 if (!(ffu_map & 1)) continue;
3206 if (This->texUnitMap[i] != tex) {
3207 device_map_stage(This, i, tex);
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3209 markTextureStagesDirty(This, i);
3212 ++tex;
3216 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3218 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3219 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3220 unsigned int i;
3222 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3223 if (sampler_type[i] && This->texUnitMap[i] != i)
3225 device_map_stage(This, i, i);
3226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3227 if (i < gl_info->limits.texture_stages)
3229 markTextureStagesDirty(This, i);
3235 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3236 const DWORD *vshader_sampler_tokens, DWORD unit)
3238 DWORD current_mapping = This->rev_tex_unit_map[unit];
3240 /* Not currently used */
3241 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3243 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3244 /* Used by a fragment sampler */
3246 if (!pshader_sampler_tokens) {
3247 /* No pixel shader, check fixed function */
3248 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3251 /* Pixel shader, check the shader's sampler map */
3252 return !pshader_sampler_tokens[current_mapping];
3255 /* Used by a vertex sampler */
3256 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3259 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3261 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3262 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3263 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3264 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3265 int i;
3267 if (ps) {
3268 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3270 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3271 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3272 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3275 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3276 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3277 if (vshader_sampler_type[i])
3279 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3281 /* Already mapped somewhere */
3282 continue;
3285 while (start >= 0) {
3286 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3288 device_map_stage(This, vsampler_idx, start);
3289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3291 --start;
3292 break;
3295 --start;
3301 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3303 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3304 BOOL vs = use_vs(This->stateBlock);
3305 BOOL ps = use_ps(This->stateBlock);
3307 * Rules are:
3308 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3309 * that would be really messy and require shader recompilation
3310 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3311 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3313 if (ps) device_map_psamplers(This, gl_info);
3314 else device_map_fixed_function_samplers(This, gl_info);
3316 if (vs) device_map_vsamplers(This, ps, gl_info);
3319 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3322 This->updateStateBlock->pixelShader = pShader;
3323 This->updateStateBlock->changed.pixelShader = TRUE;
3325 /* Handle recording of state blocks */
3326 if (This->isRecordingState) {
3327 TRACE("Recording... not performing anything\n");
3330 if (This->isRecordingState) {
3331 TRACE("Recording... not performing anything\n");
3332 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3333 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3334 return WINED3D_OK;
3337 if(pShader == oldShader) {
3338 TRACE("App is setting the old pixel shader over, nothing to do\n");
3339 return WINED3D_OK;
3342 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3343 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3345 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3348 return WINED3D_OK;
3351 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 if (NULL == ppShader) {
3355 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3356 return WINED3DERR_INVALIDCALL;
3359 *ppShader = This->stateBlock->pixelShader;
3360 if (NULL != *ppShader) {
3361 IWineD3DPixelShader_AddRef(*ppShader);
3363 TRACE("(%p) : returning %p\n", This, *ppShader);
3364 return WINED3D_OK;
3367 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3368 IWineD3DDevice *iface,
3369 UINT start,
3370 CONST BOOL *srcData,
3371 UINT count) {
3373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3374 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3376 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3377 iface, srcData, start, count);
3379 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3381 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3382 for (i = 0; i < cnt; i++)
3383 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3385 for (i = start; i < cnt + start; ++i) {
3386 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3389 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3395 IWineD3DDevice *iface,
3396 UINT start,
3397 BOOL *dstData,
3398 UINT count) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int cnt = min(count, MAX_CONST_B - start);
3403 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3404 iface, dstData, start, count);
3406 if (dstData == NULL || cnt < 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3410 return WINED3D_OK;
3413 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3414 IWineD3DDevice *iface,
3415 UINT start,
3416 CONST int *srcData,
3417 UINT count) {
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3422 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3423 iface, srcData, start, count);
3425 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3427 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3428 for (i = 0; i < cnt; i++)
3429 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3430 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3432 for (i = start; i < cnt + start; ++i) {
3433 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3436 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3438 return WINED3D_OK;
3441 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3442 IWineD3DDevice *iface,
3443 UINT start,
3444 int *dstData,
3445 UINT count) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3448 int cnt = min(count, MAX_CONST_I - start);
3450 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3451 iface, dstData, start, count);
3453 if (dstData == NULL || cnt < 0)
3454 return WINED3DERR_INVALIDCALL;
3456 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3457 return WINED3D_OK;
3460 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3461 IWineD3DDevice *iface,
3462 UINT start,
3463 CONST float *srcData,
3464 UINT count) {
3466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3467 UINT i;
3469 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3470 iface, srcData, start, count);
3472 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3473 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3474 return WINED3DERR_INVALIDCALL;
3476 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3477 if(TRACE_ON(d3d)) {
3478 for (i = 0; i < count; i++)
3479 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3480 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3483 if (!This->isRecordingState)
3485 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3489 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3490 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3492 return WINED3D_OK;
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3496 IWineD3DDevice *iface,
3497 UINT start,
3498 float *dstData,
3499 UINT count) {
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 int cnt = min(count, This->d3d_pshader_constantF - start);
3504 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3505 iface, dstData, start, count);
3507 if (dstData == NULL || cnt < 0)
3508 return WINED3DERR_INVALIDCALL;
3510 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3511 return WINED3D_OK;
3514 /* Context activation is done by the caller. */
3515 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3516 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3517 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3518 DWORD DestFVF)
3520 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3521 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3522 unsigned int i;
3523 WINED3DVIEWPORT vp;
3524 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3525 BOOL doClip;
3526 DWORD numTextures;
3528 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3530 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3533 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3535 ERR("Source has no position mask\n");
3536 return WINED3DERR_INVALIDCALL;
3539 /* We might access VBOs from this code, so hold the lock */
3540 ENTER_GL();
3542 if (dest->resource.allocatedMemory == NULL) {
3543 buffer_get_sysmem(dest);
3546 /* Get a pointer into the destination vbo(create one if none exists) and
3547 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3549 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3551 dest->flags |= WINED3D_BUFFER_CREATEBO;
3552 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3555 if (dest->buffer_object)
3557 unsigned char extrabytes = 0;
3558 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3559 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3560 * this may write 4 extra bytes beyond the area that should be written
3562 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3563 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3564 if(!dest_conv_addr) {
3565 ERR("Out of memory\n");
3566 /* Continue without storing converted vertices */
3568 dest_conv = dest_conv_addr;
3571 /* Should I clip?
3572 * a) WINED3DRS_CLIPPING is enabled
3573 * b) WINED3DVOP_CLIP is passed
3575 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3576 static BOOL warned = FALSE;
3578 * The clipping code is not quite correct. Some things need
3579 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3580 * so disable clipping for now.
3581 * (The graphics in Half-Life are broken, and my processvertices
3582 * test crashes with IDirect3DDevice3)
3583 doClip = TRUE;
3585 doClip = FALSE;
3586 if(!warned) {
3587 warned = TRUE;
3588 FIXME("Clipping is broken and disabled for now\n");
3590 } else doClip = FALSE;
3591 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3593 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3594 WINED3DTS_VIEW,
3595 &view_mat);
3596 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3597 WINED3DTS_PROJECTION,
3598 &proj_mat);
3599 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3600 WINED3DTS_WORLDMATRIX(0),
3601 &world_mat);
3603 TRACE("View mat:\n");
3604 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);
3605 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);
3606 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);
3607 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);
3609 TRACE("Proj mat:\n");
3610 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);
3611 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);
3612 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);
3613 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);
3615 TRACE("World mat:\n");
3616 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);
3617 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);
3618 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);
3619 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);
3621 /* Get the viewport */
3622 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3623 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3624 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3626 multiply_matrix(&mat,&view_mat,&world_mat);
3627 multiply_matrix(&mat,&proj_mat,&mat);
3629 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3631 for (i = 0; i < dwCount; i+= 1) {
3632 unsigned int tex_index;
3634 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3635 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3636 /* The position first */
3637 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3638 const float *p = (const float *)(element->data + i * element->stride);
3639 float x, y, z, rhw;
3640 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3642 /* Multiplication with world, view and projection matrix */
3643 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);
3644 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);
3645 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);
3646 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);
3648 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3650 /* WARNING: The following things are taken from d3d7 and were not yet checked
3651 * against d3d8 or d3d9!
3654 /* Clipping conditions: From msdn
3656 * A vertex is clipped if it does not match the following requirements
3657 * -rhw < x <= rhw
3658 * -rhw < y <= rhw
3659 * 0 < z <= rhw
3660 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3662 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3663 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3667 if( !doClip ||
3668 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3669 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3670 ( rhw > eps ) ) ) {
3672 /* "Normal" viewport transformation (not clipped)
3673 * 1) The values are divided by rhw
3674 * 2) The y axis is negative, so multiply it with -1
3675 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3676 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3677 * 4) Multiply x with Width/2 and add Width/2
3678 * 5) The same for the height
3679 * 6) Add the viewpoint X and Y to the 2D coordinates and
3680 * The minimum Z value to z
3681 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3683 * Well, basically it's simply a linear transformation into viewport
3684 * coordinates
3687 x /= rhw;
3688 y /= rhw;
3689 z /= rhw;
3691 y *= -1;
3693 x *= vp.Width / 2;
3694 y *= vp.Height / 2;
3695 z *= vp.MaxZ - vp.MinZ;
3697 x += vp.Width / 2 + vp.X;
3698 y += vp.Height / 2 + vp.Y;
3699 z += vp.MinZ;
3701 rhw = 1 / rhw;
3702 } else {
3703 /* That vertex got clipped
3704 * Contrary to OpenGL it is not dropped completely, it just
3705 * undergoes a different calculation.
3707 TRACE("Vertex got clipped\n");
3708 x += rhw;
3709 y += rhw;
3711 x /= 2;
3712 y /= 2;
3714 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3715 * outside of the main vertex buffer memory. That needs some more
3716 * investigation...
3720 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3723 ( (float *) dest_ptr)[0] = x;
3724 ( (float *) dest_ptr)[1] = y;
3725 ( (float *) dest_ptr)[2] = z;
3726 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3728 dest_ptr += 3 * sizeof(float);
3730 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3731 dest_ptr += sizeof(float);
3734 if(dest_conv) {
3735 float w = 1 / rhw;
3736 ( (float *) dest_conv)[0] = x * w;
3737 ( (float *) dest_conv)[1] = y * w;
3738 ( (float *) dest_conv)[2] = z * w;
3739 ( (float *) dest_conv)[3] = w;
3741 dest_conv += 3 * sizeof(float);
3743 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3744 dest_conv += sizeof(float);
3748 if (DestFVF & WINED3DFVF_PSIZE) {
3749 dest_ptr += sizeof(DWORD);
3750 if(dest_conv) dest_conv += sizeof(DWORD);
3752 if (DestFVF & WINED3DFVF_NORMAL) {
3753 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3754 const float *normal = (const float *)(element->data + i * element->stride);
3755 /* AFAIK this should go into the lighting information */
3756 FIXME("Didn't expect the destination to have a normal\n");
3757 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3758 if(dest_conv) {
3759 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3763 if (DestFVF & WINED3DFVF_DIFFUSE) {
3764 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3765 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3766 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3768 static BOOL warned = FALSE;
3770 if(!warned) {
3771 ERR("No diffuse color in source, but destination has one\n");
3772 warned = TRUE;
3775 *( (DWORD *) dest_ptr) = 0xffffffff;
3776 dest_ptr += sizeof(DWORD);
3778 if(dest_conv) {
3779 *( (DWORD *) dest_conv) = 0xffffffff;
3780 dest_conv += sizeof(DWORD);
3783 else {
3784 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3785 if(dest_conv) {
3786 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3787 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3788 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3789 dest_conv += sizeof(DWORD);
3794 if (DestFVF & WINED3DFVF_SPECULAR)
3796 /* What's the color value in the feedback buffer? */
3797 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3798 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3799 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3801 static BOOL warned = FALSE;
3803 if(!warned) {
3804 ERR("No specular color in source, but destination has one\n");
3805 warned = TRUE;
3808 *( (DWORD *) dest_ptr) = 0xFF000000;
3809 dest_ptr += sizeof(DWORD);
3811 if(dest_conv) {
3812 *( (DWORD *) dest_conv) = 0xFF000000;
3813 dest_conv += sizeof(DWORD);
3816 else {
3817 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3818 if(dest_conv) {
3819 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3820 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3821 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3822 dest_conv += sizeof(DWORD);
3827 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3828 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3829 const float *tex_coord = (const float *)(element->data + i * element->stride);
3830 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3832 ERR("No source texture, but destination requests one\n");
3833 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3834 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3836 else {
3837 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3838 if(dest_conv) {
3839 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3845 if(dest_conv) {
3846 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3847 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3848 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3849 dwCount * get_flexible_vertex_size(DestFVF),
3850 dest_conv_addr));
3851 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3852 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3855 LEAVE_GL();
3857 return WINED3D_OK;
3859 #undef copy_and_next
3861 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3862 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3863 DWORD DestFVF)
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 struct wined3d_stream_info stream_info;
3867 struct wined3d_context *context;
3868 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3869 HRESULT hr;
3871 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3873 if(pVertexDecl) {
3874 ERR("Output vertex declaration not implemented yet\n");
3877 /* Need any context to write to the vbo. */
3878 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3880 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3881 * control the streamIsUP flag, thus restore it afterwards.
3883 This->stateBlock->streamIsUP = FALSE;
3884 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3885 This->stateBlock->streamIsUP = streamWasUP;
3887 if(vbo || SrcStartIndex) {
3888 unsigned int i;
3889 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3890 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3892 * Also get the start index in, but only loop over all elements if there's something to add at all.
3894 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3896 struct wined3d_stream_info_element *e;
3898 if (!(stream_info.use_map & (1 << i))) continue;
3900 e = &stream_info.elements[i];
3901 if (e->buffer_object)
3903 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3904 e->buffer_object = 0;
3905 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3906 ENTER_GL();
3907 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3908 vb->buffer_object = 0;
3909 LEAVE_GL();
3911 if (e->data) e->data += e->stride * SrcStartIndex;
3915 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3916 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3918 context_release(context);
3920 return hr;
3923 /*****
3924 * Get / Set Texture Stage States
3925 * TODO: Verify against dx9 definitions
3926 *****/
3927 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3929 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3930 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3932 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3934 if (Stage >= gl_info->limits.texture_stages)
3936 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3937 Stage, gl_info->limits.texture_stages - 1);
3938 return WINED3D_OK;
3941 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3942 This->updateStateBlock->textureState[Stage][Type] = Value;
3944 if (This->isRecordingState) {
3945 TRACE("Recording... not performing anything\n");
3946 return WINED3D_OK;
3949 /* Checked after the assignments to allow proper stateblock recording */
3950 if(oldValue == Value) {
3951 TRACE("App is setting the old value over, nothing to do\n");
3952 return WINED3D_OK;
3955 if(Stage > This->stateBlock->lowest_disabled_stage &&
3956 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3957 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3958 * Changes in other states are important on disabled stages too
3960 return WINED3D_OK;
3963 if(Type == WINED3DTSS_COLOROP) {
3964 unsigned int i;
3966 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3967 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3968 * they have to be disabled
3970 * The current stage is dirtified below.
3972 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3973 TRACE("Additionally dirtifying stage %u\n", i);
3974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3976 This->stateBlock->lowest_disabled_stage = Stage;
3977 TRACE("New lowest disabled: %u\n", Stage);
3978 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3979 /* Previously disabled stage enabled. Stages above it may need enabling
3980 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3981 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3983 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3986 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3988 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3989 break;
3991 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3994 This->stateBlock->lowest_disabled_stage = i;
3995 TRACE("New lowest disabled: %u\n", i);
3999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4001 return WINED3D_OK;
4004 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4007 *pValue = This->updateStateBlock->textureState[Stage][Type];
4008 return WINED3D_OK;
4011 /*****
4012 * Get / Set Texture
4013 *****/
4014 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4015 DWORD stage, IWineD3DBaseTexture *texture)
4017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4018 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4019 IWineD3DBaseTexture *prev;
4021 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4023 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4024 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4026 /* Windows accepts overflowing this array... we do not. */
4027 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4029 WARN("Ignoring invalid stage %u.\n", stage);
4030 return WINED3D_OK;
4033 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4034 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4036 WARN("Rejecting attempt to set scratch texture.\n");
4037 return WINED3DERR_INVALIDCALL;
4040 This->updateStateBlock->changed.textures |= 1 << stage;
4042 prev = This->updateStateBlock->textures[stage];
4043 TRACE("Previous texture %p.\n", prev);
4045 if (texture == prev)
4047 TRACE("App is setting the same texture again, nothing to do.\n");
4048 return WINED3D_OK;
4051 TRACE("Setting new texture to %p.\n", texture);
4052 This->updateStateBlock->textures[stage] = texture;
4054 if (This->isRecordingState)
4056 TRACE("Recording... not performing anything\n");
4058 if (texture) IWineD3DBaseTexture_AddRef(texture);
4059 if (prev) IWineD3DBaseTexture_Release(prev);
4061 return WINED3D_OK;
4064 if (texture)
4066 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4067 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4068 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4070 IWineD3DBaseTexture_AddRef(texture);
4072 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4077 if (!prev && stage < gl_info->limits.texture_stages)
4079 /* The source arguments for color and alpha ops have different
4080 * meanings when a NULL texture is bound, so the COLOROP and
4081 * ALPHAOP have to be dirtified. */
4082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4083 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4086 if (bind_count == 1) t->baseTexture.sampler = stage;
4089 if (prev)
4091 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4092 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4094 IWineD3DBaseTexture_Release(prev);
4096 if (!texture && stage < gl_info->limits.texture_stages)
4098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4102 if (bind_count && t->baseTexture.sampler == stage)
4104 unsigned int i;
4106 /* Search for other stages the texture is bound to. Shouldn't
4107 * happen if applications bind textures to a single stage only. */
4108 TRACE("Searching for other stages the texture is bound to.\n");
4109 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4111 if (This->updateStateBlock->textures[i] == prev)
4113 TRACE("Texture is also bound to stage %u.\n", i);
4114 t->baseTexture.sampler = i;
4115 break;
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4123 return WINED3D_OK;
4126 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4129 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4131 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4132 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4135 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4136 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4137 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4140 *ppTexture=This->stateBlock->textures[Stage];
4141 if (*ppTexture)
4142 IWineD3DBaseTexture_AddRef(*ppTexture);
4144 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4146 return WINED3D_OK;
4149 /*****
4150 * Get Back Buffer
4151 *****/
4152 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4153 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4155 IWineD3DSwapChain *swapchain;
4156 HRESULT hr;
4158 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4159 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4161 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4162 if (FAILED(hr))
4164 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4165 return hr;
4168 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4169 IWineD3DSwapChain_Release(swapchain);
4170 if (FAILED(hr))
4172 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4173 return hr;
4176 return WINED3D_OK;
4179 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 WARN("(%p) : stub, calling idirect3d for now\n", This);
4182 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4185 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4187 IWineD3DSwapChain *swapChain;
4188 HRESULT hr;
4190 if(iSwapChain > 0) {
4191 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4192 if (hr == WINED3D_OK) {
4193 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4194 IWineD3DSwapChain_Release(swapChain);
4195 } else {
4196 FIXME("(%p) Error getting display mode\n", This);
4198 } else {
4199 /* Don't read the real display mode,
4200 but return the stored mode instead. X11 can't change the color
4201 depth, and some apps are pretty angry if they SetDisplayMode from
4202 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4204 Also don't relay to the swapchain because with ddraw it's possible
4205 that there isn't a swapchain at all */
4206 pMode->Width = This->ddraw_width;
4207 pMode->Height = This->ddraw_height;
4208 pMode->Format = This->ddraw_format;
4209 pMode->RefreshRate = 0;
4210 hr = WINED3D_OK;
4213 return hr;
4216 /*****
4217 * Stateblock related functions
4218 *****/
4220 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4222 IWineD3DStateBlock *stateblock;
4223 HRESULT hr;
4225 TRACE("(%p)\n", This);
4227 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4229 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4230 if (FAILED(hr)) return hr;
4232 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4233 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4234 This->isRecordingState = TRUE;
4236 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4238 return WINED3D_OK;
4241 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4245 if (!This->isRecordingState) {
4246 WARN("(%p) not recording! returning error\n", This);
4247 *ppStateBlock = NULL;
4248 return WINED3DERR_INVALIDCALL;
4251 stateblock_init_contained_states(object);
4253 *ppStateBlock = (IWineD3DStateBlock*) object;
4254 This->isRecordingState = FALSE;
4255 This->updateStateBlock = This->stateBlock;
4256 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4257 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4258 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4259 return WINED3D_OK;
4262 /*****
4263 * Scene related functions
4264 *****/
4265 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4266 /* At the moment we have no need for any functionality at the beginning
4267 of a scene */
4268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4269 TRACE("(%p)\n", This);
4271 if(This->inScene) {
4272 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4273 return WINED3DERR_INVALIDCALL;
4275 This->inScene = TRUE;
4276 return WINED3D_OK;
4279 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4282 struct wined3d_context *context;
4284 TRACE("(%p)\n", This);
4286 if(!This->inScene) {
4287 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4288 return WINED3DERR_INVALIDCALL;
4291 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4292 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4293 wglFlush();
4294 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4295 * fails. */
4296 context_release(context);
4298 This->inScene = FALSE;
4299 return WINED3D_OK;
4302 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4303 const RECT *pSourceRect, const RECT *pDestRect,
4304 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4306 IWineD3DSwapChain *swapChain = NULL;
4307 int i;
4308 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4310 TRACE("iface %p.\n", iface);
4312 for(i = 0 ; i < swapchains ; i ++) {
4314 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4315 TRACE("presentinng chain %d, %p\n", i, swapChain);
4316 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4317 IWineD3DSwapChain_Release(swapChain);
4320 return WINED3D_OK;
4323 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4324 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4326 /* partial viewport*/
4327 if (viewport->X != 0 || viewport->Y != 0
4328 || viewport->Width < target->currentDesc.Width
4329 || viewport->Height < target->currentDesc.Height)
4330 return FALSE;
4332 /* partial scissor rect */
4333 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4334 || scissor_rect->right < target->currentDesc.Width
4335 || scissor_rect->bottom < target->currentDesc.Height))
4336 return FALSE;
4338 /* partial clear rect */
4339 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4340 || clear_rect->x2 < target->currentDesc.Width
4341 || clear_rect->y2 < target->currentDesc.Height))
4342 return FALSE;
4344 return TRUE;
4347 /* Not called from the VTable (internal subroutine) */
4348 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4349 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4351 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4352 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4353 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4354 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4355 GLbitfield glMask = 0;
4356 unsigned int i;
4357 WINED3DRECT curRect;
4358 RECT vp_rect;
4359 UINT drawable_width, drawable_height;
4360 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4361 struct wined3d_context *context;
4363 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4364 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4365 * for the cleared parts, and the untouched parts.
4367 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4368 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4369 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4370 * checking all this if the dest surface is in the drawable anyway.
4372 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4374 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4375 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4378 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4379 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4381 if (!surface_is_offscreen(target))
4383 TRACE("Surface %p is onscreen\n", target);
4385 ENTER_GL();
4386 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4387 context_set_draw_buffer(context, surface_get_gl_buffer((IWineD3DSurface *)target));
4388 LEAVE_GL();
4390 else
4392 TRACE("Surface %p is offscreen\n", target);
4394 ENTER_GL();
4395 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4396 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, target);
4397 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, depth_stencil, TRUE);
4398 LEAVE_GL();
4402 if (!context->valid)
4404 context_release(context);
4405 WARN("Invalid context, skipping clear.\n");
4406 return WINED3D_OK;
4409 target->get_drawable_size(context, &drawable_width, &drawable_height);
4411 ENTER_GL();
4413 /* Only set the values up once, as they are not changing */
4414 if (Flags & WINED3DCLEAR_STENCIL)
4416 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4418 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4421 glStencilMask(~0U);
4422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4423 glClearStencil(Stencil);
4424 checkGLcall("glClearStencil");
4425 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4428 if (Flags & WINED3DCLEAR_ZBUFFER)
4430 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4431 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4432 surface_load_ds_location(depth_stencil, context, location);
4434 glDepthMask(GL_TRUE);
4435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4436 glClearDepth(Z);
4437 checkGLcall("glClearDepth");
4438 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4441 if (Flags & WINED3DCLEAR_TARGET)
4443 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4448 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4449 checkGLcall("glClearColor");
4450 glMask = glMask | GL_COLOR_BUFFER_BIT;
4453 vp_rect.left = vp->X;
4454 vp_rect.top = vp->Y;
4455 vp_rect.right = vp->X + vp->Width;
4456 vp_rect.bottom = vp->Y + vp->Height;
4457 if (!(Count > 0 && pRects)) {
4458 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4459 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4461 if (context->render_offscreen)
4463 glScissor(vp_rect.left, vp_rect.top,
4464 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4465 } else {
4466 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4467 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4469 checkGLcall("glScissor");
4470 glClear(glMask);
4471 checkGLcall("glClear");
4472 } else {
4473 /* Now process each rect in turn */
4474 for (i = 0; i < Count; i++) {
4475 /* Note gl uses lower left, width/height */
4476 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4477 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4478 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4480 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4481 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4482 curRect.x1, (target->currentDesc.Height - curRect.y2),
4483 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4485 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4486 * The rectangle is not cleared, no error is returned, but further rectanlges are
4487 * still cleared if they are valid
4489 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4490 TRACE("Rectangle with negative dimensions, ignoring\n");
4491 continue;
4494 if (context->render_offscreen)
4496 glScissor(curRect.x1, curRect.y1,
4497 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4498 } else {
4499 glScissor(curRect.x1, drawable_height - curRect.y2,
4500 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4502 checkGLcall("glScissor");
4504 glClear(glMask);
4505 checkGLcall("glClear");
4509 if (Flags & WINED3DCLEAR_TARGET)
4511 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4513 if (Flags & WINED3DCLEAR_ZBUFFER) {
4514 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4515 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4516 surface_modify_ds_location(depth_stencil, location);
4519 LEAVE_GL();
4521 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4522 && ((IWineD3DSwapChainImpl *)target->container)->frontBuffer == (IWineD3DSurface *)target))
4523 wglFlush(); /* Flush to ensure ordering across contexts. */
4525 context_release(context);
4527 return WINED3D_OK;
4530 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4531 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4533 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4535 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4536 Count, pRects, Flags, Color, Z, Stencil);
4538 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4539 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4540 /* TODO: What about depth stencil buffers without stencil bits? */
4541 return WINED3DERR_INVALIDCALL;
4544 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4547 /*****
4548 * Drawing functions
4549 *****/
4551 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4552 WINED3DPRIMITIVETYPE primitive_type)
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4556 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4558 This->updateStateBlock->changed.primitive_type = TRUE;
4559 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4562 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4563 WINED3DPRIMITIVETYPE *primitive_type)
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4567 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4569 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4571 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4574 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4580 if(!This->stateBlock->vertexDecl) {
4581 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4582 return WINED3DERR_INVALIDCALL;
4585 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4586 if(This->stateBlock->streamIsUP) {
4587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4588 This->stateBlock->streamIsUP = FALSE;
4591 if(This->stateBlock->loadBaseVertexIndex != 0) {
4592 This->stateBlock->loadBaseVertexIndex = 0;
4593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4595 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4596 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4597 return WINED3D_OK;
4600 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 UINT idxStride = 2;
4604 IWineD3DBuffer *pIB;
4605 GLuint vbo;
4607 pIB = This->stateBlock->pIndexData;
4608 if (!pIB) {
4609 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4610 * without an index buffer set. (The first time at least...)
4611 * D3D8 simply dies, but I doubt it can do much harm to return
4612 * D3DERR_INVALIDCALL there as well. */
4613 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4614 return WINED3DERR_INVALIDCALL;
4617 if(!This->stateBlock->vertexDecl) {
4618 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4619 return WINED3DERR_INVALIDCALL;
4622 if(This->stateBlock->streamIsUP) {
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4624 This->stateBlock->streamIsUP = FALSE;
4626 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4628 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4630 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4631 idxStride = 2;
4632 } else {
4633 idxStride = 4;
4636 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4637 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4641 drawPrimitive(iface, index_count, startIndex, idxStride,
4642 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4644 return WINED3D_OK;
4647 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4648 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 IWineD3DBuffer *vb;
4653 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4654 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4656 if(!This->stateBlock->vertexDecl) {
4657 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4658 return WINED3DERR_INVALIDCALL;
4661 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4662 vb = This->stateBlock->streamSource[0];
4663 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4664 if (vb) IWineD3DBuffer_Release(vb);
4665 This->stateBlock->streamOffset[0] = 0;
4666 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4667 This->stateBlock->streamIsUP = TRUE;
4668 This->stateBlock->loadBaseVertexIndex = 0;
4670 /* TODO: Only mark dirty if drawing from a different UP address */
4671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4673 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4675 /* MSDN specifies stream zero settings must be set to NULL */
4676 This->stateBlock->streamStride[0] = 0;
4677 This->stateBlock->streamSource[0] = NULL;
4679 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4680 * the new stream sources or use UP drawing again
4682 return WINED3D_OK;
4685 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4686 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4687 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4689 int idxStride;
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 IWineD3DBuffer *vb;
4692 IWineD3DBuffer *ib;
4694 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4695 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4697 if(!This->stateBlock->vertexDecl) {
4698 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4699 return WINED3DERR_INVALIDCALL;
4702 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4703 idxStride = 2;
4704 } else {
4705 idxStride = 4;
4708 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4709 vb = This->stateBlock->streamSource[0];
4710 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4711 if (vb) IWineD3DBuffer_Release(vb);
4712 This->stateBlock->streamIsUP = TRUE;
4713 This->stateBlock->streamOffset[0] = 0;
4714 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4716 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4717 This->stateBlock->baseVertexIndex = 0;
4718 This->stateBlock->loadBaseVertexIndex = 0;
4719 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4723 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4725 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4726 This->stateBlock->streamSource[0] = NULL;
4727 This->stateBlock->streamStride[0] = 0;
4728 ib = This->stateBlock->pIndexData;
4729 if(ib) {
4730 IWineD3DBuffer_Release(ib);
4731 This->stateBlock->pIndexData = NULL;
4733 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4734 * SetStreamSource to specify a vertex buffer
4737 return WINED3D_OK;
4740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4741 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4745 /* Mark the state dirty until we have nicer tracking
4746 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4747 * that value.
4749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4751 This->stateBlock->baseVertexIndex = 0;
4752 This->up_strided = DrawPrimStrideData;
4753 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4754 This->up_strided = NULL;
4755 return WINED3D_OK;
4758 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4759 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4760 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4763 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4765 /* Mark the state dirty until we have nicer tracking
4766 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4767 * that value.
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4771 This->stateBlock->streamIsUP = TRUE;
4772 This->stateBlock->baseVertexIndex = 0;
4773 This->up_strided = DrawPrimStrideData;
4774 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4775 This->up_strided = NULL;
4776 return WINED3D_OK;
4779 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4780 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4781 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4783 WINED3DLOCKED_BOX src;
4784 WINED3DLOCKED_BOX dst;
4785 HRESULT hr;
4787 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4788 iface, pSourceVolume, pDestinationVolume);
4790 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4791 * dirtification to improve loading performance.
4793 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4794 if(FAILED(hr)) return hr;
4795 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4796 if(FAILED(hr)) {
4797 IWineD3DVolume_UnlockBox(pSourceVolume);
4798 return hr;
4801 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4803 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4804 if(FAILED(hr)) {
4805 IWineD3DVolume_UnlockBox(pSourceVolume);
4806 } else {
4807 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4809 return hr;
4812 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4813 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4815 unsigned int level_count, i;
4816 WINED3DRESOURCETYPE type;
4817 HRESULT hr;
4819 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4821 /* Verify that the source and destination textures are non-NULL. */
4822 if (!src_texture || !dst_texture)
4824 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4825 return WINED3DERR_INVALIDCALL;
4828 if (src_texture == dst_texture)
4830 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4831 return WINED3DERR_INVALIDCALL;
4834 /* Verify that the source and destination textures are the same type. */
4835 type = IWineD3DBaseTexture_GetType(src_texture);
4836 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4838 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4839 return WINED3DERR_INVALIDCALL;
4842 /* Check that both textures have the identical numbers of levels. */
4843 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4844 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4846 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4847 return WINED3DERR_INVALIDCALL;
4850 /* Make sure that the destination texture is loaded. */
4851 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4853 /* Update every surface level of the texture. */
4854 switch (type)
4856 case WINED3DRTYPE_TEXTURE:
4858 IWineD3DSurface *src_surface;
4859 IWineD3DSurface *dst_surface;
4861 for (i = 0; i < level_count; ++i)
4863 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4864 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4865 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4866 IWineD3DSurface_Release(dst_surface);
4867 IWineD3DSurface_Release(src_surface);
4868 if (FAILED(hr))
4870 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4871 return hr;
4874 break;
4877 case WINED3DRTYPE_CUBETEXTURE:
4879 IWineD3DSurface *src_surface;
4880 IWineD3DSurface *dst_surface;
4881 WINED3DCUBEMAP_FACES face;
4883 for (i = 0; i < level_count; ++i)
4885 /* Update each cube face. */
4886 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4888 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4889 face, i, &src_surface);
4890 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4891 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4892 face, i, &dst_surface);
4893 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4894 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4895 IWineD3DSurface_Release(dst_surface);
4896 IWineD3DSurface_Release(src_surface);
4897 if (FAILED(hr))
4899 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4900 return hr;
4904 break;
4907 case WINED3DRTYPE_VOLUMETEXTURE:
4909 IWineD3DVolume *src_volume;
4910 IWineD3DVolume *dst_volume;
4912 for (i = 0; i < level_count; ++i)
4914 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4915 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4916 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4917 IWineD3DVolume_Release(dst_volume);
4918 IWineD3DVolume_Release(src_volume);
4919 if (FAILED(hr))
4921 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4922 return hr;
4925 break;
4928 default:
4929 FIXME("Unsupported texture type %#x.\n", type);
4930 return WINED3DERR_INVALIDCALL;
4933 return WINED3D_OK;
4936 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4937 IWineD3DSwapChain *swapChain;
4938 HRESULT hr;
4939 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4940 if(hr == WINED3D_OK) {
4941 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4942 IWineD3DSwapChain_Release(swapChain);
4944 return hr;
4947 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4949 IWineD3DBaseTextureImpl *texture;
4950 DWORD i;
4952 TRACE("(%p) : %p\n", This, pNumPasses);
4954 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4955 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4956 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4957 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4959 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4960 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4961 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4964 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4965 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4967 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4968 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4969 return E_FAIL;
4971 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4972 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4973 return E_FAIL;
4975 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4976 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4977 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4978 return E_FAIL;
4982 /* return a sensible default */
4983 *pNumPasses = 1;
4985 TRACE("returning D3D_OK\n");
4986 return WINED3D_OK;
4989 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4991 int i;
4993 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4995 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4996 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4997 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4999 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5004 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5006 int j;
5007 UINT NewSize;
5008 PALETTEENTRY **palettes;
5010 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5012 if (PaletteNumber >= MAX_PALETTES) {
5013 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5014 return WINED3DERR_INVALIDCALL;
5017 if (PaletteNumber >= This->NumberOfPalettes) {
5018 NewSize = This->NumberOfPalettes;
5019 do {
5020 NewSize *= 2;
5021 } while(PaletteNumber >= NewSize);
5022 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5023 if (!palettes) {
5024 ERR("Out of memory!\n");
5025 return E_OUTOFMEMORY;
5027 This->palettes = palettes;
5028 This->NumberOfPalettes = NewSize;
5031 if (!This->palettes[PaletteNumber]) {
5032 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5033 if (!This->palettes[PaletteNumber]) {
5034 ERR("Out of memory!\n");
5035 return E_OUTOFMEMORY;
5039 for (j = 0; j < 256; ++j) {
5040 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5041 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5042 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5043 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5045 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5046 TRACE("(%p) : returning\n", This);
5047 return WINED3D_OK;
5050 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5052 int j;
5053 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5054 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5055 /* What happens in such situation isn't documented; Native seems to silently abort
5056 on such conditions. Return Invalid Call. */
5057 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5058 return WINED3DERR_INVALIDCALL;
5060 for (j = 0; j < 256; ++j) {
5061 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5062 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5063 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5064 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5066 TRACE("(%p) : returning\n", This);
5067 return WINED3D_OK;
5070 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5073 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5074 (tested with reference rasterizer). Return Invalid Call. */
5075 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5076 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5077 return WINED3DERR_INVALIDCALL;
5079 /*TODO: stateblocks */
5080 if (This->currentPalette != PaletteNumber) {
5081 This->currentPalette = PaletteNumber;
5082 dirtify_p8_texture_samplers(This);
5084 TRACE("(%p) : returning\n", This);
5085 return WINED3D_OK;
5088 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5090 if (PaletteNumber == NULL) {
5091 WARN("(%p) : returning Invalid Call\n", This);
5092 return WINED3DERR_INVALIDCALL;
5094 /*TODO: stateblocks */
5095 *PaletteNumber = This->currentPalette;
5096 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5097 return WINED3D_OK;
5100 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 static BOOL warned;
5103 if (!warned)
5105 FIXME("(%p) : stub\n", This);
5106 warned = TRUE;
5109 This->softwareVertexProcessing = bSoftware;
5110 return WINED3D_OK;
5114 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5116 static BOOL warned;
5117 if (!warned)
5119 FIXME("(%p) : stub\n", This);
5120 warned = TRUE;
5122 return This->softwareVertexProcessing;
5125 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5126 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5128 IWineD3DSwapChain *swapchain;
5129 HRESULT hr;
5131 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5132 iface, swapchain_idx, raster_status);
5134 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5135 if (FAILED(hr))
5137 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5138 return hr;
5141 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5142 IWineD3DSwapChain_Release(swapchain);
5143 if (FAILED(hr))
5145 WARN("Failed to get raster status, hr %#x.\n", hr);
5146 return hr;
5149 return WINED3D_OK;
5152 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5154 static BOOL warned;
5155 if(nSegments != 0.0f) {
5156 if (!warned)
5158 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5159 warned = TRUE;
5162 return WINED3D_OK;
5165 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5167 static BOOL warned;
5168 if (!warned)
5170 FIXME("iface %p stub!\n", iface);
5171 warned = TRUE;
5173 return 0.0f;
5176 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5177 IWineD3DSurface *src_surface, const RECT *src_rect,
5178 IWineD3DSurface *dst_surface, const POINT *dst_point)
5180 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5181 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5183 const struct wined3d_format_desc *src_format;
5184 const struct wined3d_format_desc *dst_format;
5185 struct wined3d_context *context;
5186 const unsigned char *data;
5187 UINT update_w, update_h;
5188 CONVERT_TYPES convert;
5189 UINT src_w, src_h;
5190 UINT dst_x, dst_y;
5191 DWORD sampler;
5192 struct wined3d_format_desc dummy_desc;
5194 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s",
5195 iface, src_surface, wine_dbgstr_rect(src_rect),
5196 dst_surface, wine_dbgstr_point(dst_point));
5198 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5200 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5201 src_surface, dst_surface);
5202 return WINED3DERR_INVALIDCALL;
5205 src_format = src_impl->resource.format_desc;
5206 dst_format = dst_impl->resource.format_desc;
5208 if (src_format->format != dst_format->format)
5210 WARN("Source and destination surfaces should have the same format.\n");
5211 return WINED3DERR_INVALIDCALL;
5214 dst_x = dst_point ? dst_point->x : 0;
5215 dst_y = dst_point ? dst_point->y : 0;
5217 /* This call loads the OpenGL surface directly, instead of copying the
5218 * surface to the destination's sysmem copy. If surface conversion is
5219 * needed, use BltFast instead to copy in sysmem and use regular surface
5220 * loading. */
5221 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5222 if (convert != NO_CONVERSION)
5223 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5225 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5227 ENTER_GL();
5228 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5229 checkGLcall("glActiveTextureARB");
5230 LEAVE_GL();
5232 /* Make sure the surface is loaded and up to date */
5233 surface_internal_preload(dst_surface, SRGB_RGB);
5234 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5236 src_w = src_impl->currentDesc.Width;
5237 src_h = src_impl->currentDesc.Height;
5238 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5239 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5241 data = IWineD3DSurface_GetData(src_surface);
5242 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5244 ENTER_GL();
5246 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5248 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5249 UINT row_count = update_h / src_format->block_height;
5250 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5252 if (src_rect)
5254 data += (src_rect->top / src_format->block_height) * src_pitch;
5255 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5258 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5259 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5260 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5262 if (row_length == src_pitch)
5264 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5265 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5267 else
5269 UINT row, y;
5271 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5272 * can't use the unpack row length like below. */
5273 for (row = 0, y = dst_y; row < row_count; ++row)
5275 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5276 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5277 y += src_format->block_height;
5278 data += src_pitch;
5281 checkGLcall("glCompressedTexSubImage2DARB");
5283 else
5285 if (src_rect)
5287 data += src_rect->top * src_w * src_format->byte_count;
5288 data += src_rect->left * src_format->byte_count;
5291 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5292 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5293 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5295 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5296 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5297 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5298 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5299 checkGLcall("glTexSubImage2D");
5302 LEAVE_GL();
5303 context_release(context);
5305 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5306 sampler = This->rev_tex_unit_map[0];
5307 if (sampler != WINED3D_UNMAPPED_STAGE)
5309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5312 return WINED3D_OK;
5315 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 struct WineD3DRectPatch *patch;
5318 GLenum old_primitive_type;
5319 unsigned int i;
5320 struct list *e;
5321 BOOL found;
5322 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5324 if(!(Handle || pRectPatchInfo)) {
5325 /* TODO: Write a test for the return value, thus the FIXME */
5326 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5327 return WINED3DERR_INVALIDCALL;
5330 if(Handle) {
5331 i = PATCHMAP_HASHFUNC(Handle);
5332 found = FALSE;
5333 LIST_FOR_EACH(e, &This->patches[i]) {
5334 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5335 if(patch->Handle == Handle) {
5336 found = TRUE;
5337 break;
5341 if(!found) {
5342 TRACE("Patch does not exist. Creating a new one\n");
5343 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5344 patch->Handle = Handle;
5345 list_add_head(&This->patches[i], &patch->entry);
5346 } else {
5347 TRACE("Found existing patch %p\n", patch);
5349 } else {
5350 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5351 * attributes we have to tesselate, read back, and draw. This needs a patch
5352 * management structure instance. Create one.
5354 * A possible improvement is to check if a vertex shader is used, and if not directly
5355 * draw the patch.
5357 FIXME("Drawing an uncached patch. This is slow\n");
5358 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5361 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5362 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5363 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5364 HRESULT hr;
5365 TRACE("Tesselation density or patch info changed, retesselating\n");
5367 if(pRectPatchInfo) {
5368 patch->RectPatchInfo = *pRectPatchInfo;
5370 patch->numSegs[0] = pNumSegs[0];
5371 patch->numSegs[1] = pNumSegs[1];
5372 patch->numSegs[2] = pNumSegs[2];
5373 patch->numSegs[3] = pNumSegs[3];
5375 hr = tesselate_rectpatch(This, patch);
5376 if(FAILED(hr)) {
5377 WARN("Patch tesselation failed\n");
5379 /* Do not release the handle to store the params of the patch */
5380 if(!Handle) {
5381 HeapFree(GetProcessHeap(), 0, patch);
5383 return hr;
5387 This->currentPatch = patch;
5388 old_primitive_type = This->stateBlock->gl_primitive_type;
5389 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5390 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5391 This->stateBlock->gl_primitive_type = old_primitive_type;
5392 This->currentPatch = NULL;
5394 /* Destroy uncached patches */
5395 if(!Handle) {
5396 HeapFree(GetProcessHeap(), 0, patch->mem);
5397 HeapFree(GetProcessHeap(), 0, patch);
5399 return WINED3D_OK;
5402 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5403 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5405 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5406 iface, handle, segment_count, patch_info);
5408 return WINED3D_OK;
5411 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 int i;
5414 struct WineD3DRectPatch *patch;
5415 struct list *e;
5416 TRACE("(%p) Handle(%d)\n", This, Handle);
5418 i = PATCHMAP_HASHFUNC(Handle);
5419 LIST_FOR_EACH(e, &This->patches[i]) {
5420 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5421 if(patch->Handle == Handle) {
5422 TRACE("Deleting patch %p\n", patch);
5423 list_remove(&patch->entry);
5424 HeapFree(GetProcessHeap(), 0, patch->mem);
5425 HeapFree(GetProcessHeap(), 0, patch);
5426 return WINED3D_OK;
5430 /* TODO: Write a test for the return value */
5431 FIXME("Attempt to destroy nonexistent patch\n");
5432 return WINED3DERR_INVALIDCALL;
5435 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5436 const WINED3DRECT *rect, const float color[4])
5438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5439 struct wined3d_context *context;
5441 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5442 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5444 if (!surface_is_offscreen((IWineD3DSurfaceImpl *)surface))
5446 TRACE("Surface %p is onscreen\n", surface);
5448 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5449 ENTER_GL();
5450 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5451 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5453 else
5455 TRACE("Surface %p is offscreen\n", surface);
5457 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5458 ENTER_GL();
5459 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5460 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)surface);
5461 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5464 if (rect) {
5465 glEnable(GL_SCISSOR_TEST);
5466 if (surface_is_offscreen((IWineD3DSurfaceImpl *)surface))
5467 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5468 else
5469 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5470 rect->x2 - rect->x1, rect->y2 - rect->y1);
5471 checkGLcall("glScissor");
5472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5473 } else {
5474 glDisable(GL_SCISSOR_TEST);
5476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5478 glDisable(GL_BLEND);
5479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5481 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5487 glClearColor(color[0], color[1], color[2], color[3]);
5488 glClear(GL_COLOR_BUFFER_BIT);
5489 checkGLcall("glClear");
5491 LEAVE_GL();
5493 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5495 context_release(context);
5498 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5499 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5501 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5502 WINEDDBLTFX BltFx;
5504 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5506 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5507 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5508 return WINED3DERR_INVALIDCALL;
5511 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5512 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5513 color_fill_fbo(iface, pSurface, pRect, c);
5514 return WINED3D_OK;
5515 } else {
5516 /* Just forward this to the DirectDraw blitting engine */
5517 memset(&BltFx, 0, sizeof(BltFx));
5518 BltFx.dwSize = sizeof(BltFx);
5519 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5520 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5521 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5525 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5526 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5528 IWineD3DResource *resource;
5529 IWineD3DSurface *surface;
5530 HRESULT hr;
5532 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5533 if (FAILED(hr))
5535 ERR("Failed to get resource, hr %#x\n", hr);
5536 return;
5539 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5541 FIXME("Only supported on surface resources\n");
5542 IWineD3DResource_Release(resource);
5543 return;
5546 surface = (IWineD3DSurface *)resource;
5548 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5550 color_fill_fbo(iface, surface, NULL, color);
5552 else
5554 WINEDDBLTFX BltFx;
5555 WINED3DCOLOR c;
5557 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5559 c = ((DWORD)(color[2] * 255.0f));
5560 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5561 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5562 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5564 /* Just forward this to the DirectDraw blitting engine */
5565 memset(&BltFx, 0, sizeof(BltFx));
5566 BltFx.dwSize = sizeof(BltFx);
5567 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5568 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5569 if (FAILED(hr))
5571 ERR("Blt failed, hr %#x\n", hr);
5575 IWineD3DResource_Release(resource);
5578 /* rendertarget and depth stencil functions */
5579 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5582 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5584 ERR("(%p) : Only %d render targets are supported.\n",
5585 This, This->adapter->gl_info.limits.buffers);
5586 return WINED3DERR_INVALIDCALL;
5589 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5590 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5591 /* Note inc ref on returned surface */
5592 if(*ppRenderTarget != NULL)
5593 IWineD3DSurface_AddRef(*ppRenderTarget);
5594 return WINED3D_OK;
5597 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5598 IWineD3DSurface *front, IWineD3DSurface *back)
5600 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5601 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5602 IWineD3DSwapChainImpl *swapchain;
5603 HRESULT hr;
5605 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5607 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5609 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5610 return hr;
5613 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5615 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5616 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5617 return WINED3DERR_INVALIDCALL;
5620 if (back_impl)
5622 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5624 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5625 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5626 return WINED3DERR_INVALIDCALL;
5629 if (!swapchain->backBuffer)
5631 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5632 if (!swapchain->backBuffer)
5634 ERR("Failed to allocate back buffer array memory.\n");
5635 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5636 return E_OUTOFMEMORY;
5641 if (swapchain->frontBuffer != front)
5643 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5645 if (swapchain->frontBuffer)
5647 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5648 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5650 swapchain->frontBuffer = front;
5652 if (front)
5654 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5655 front_impl->Flags |= SFLAG_SWAPCHAIN;
5659 if (swapchain->backBuffer[0] != back)
5661 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5663 if (swapchain->backBuffer[0])
5665 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5666 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5668 swapchain->backBuffer[0] = back;
5670 if (back)
5672 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5673 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5674 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5675 swapchain->presentParms.BackBufferCount = 1;
5677 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5678 back_impl->Flags |= SFLAG_SWAPCHAIN;
5680 else
5682 swapchain->presentParms.BackBufferCount = 0;
5683 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5684 swapchain->backBuffer = NULL;
5688 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5689 return WINED3D_OK;
5692 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5694 *ppZStencilSurface = This->stencilBufferTarget;
5695 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5697 if(*ppZStencilSurface != NULL) {
5698 /* Note inc ref on returned surface */
5699 IWineD3DSurface_AddRef(*ppZStencilSurface);
5700 return WINED3D_OK;
5701 } else {
5702 return WINED3DERR_NOTFOUND;
5706 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, const RECT *src_rect_in,
5707 IWineD3DSurface *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5711 const struct wined3d_gl_info *gl_info;
5712 struct wined3d_context *context;
5713 GLenum gl_filter;
5714 POINT offset = {0, 0};
5715 RECT src_rect, dst_rect;
5717 TRACE("(%p) : src_surface %p, src_rect_in %p, dst_surface %p, dst_rect_in %p, filter %s (0x%08x)\n",
5718 This, src_surface, src_rect_in, dst_surface, dst_rect_in, debug_d3dtexturefiltertype(filter), filter);
5719 TRACE("src_rect_in %s\n", wine_dbgstr_rect(src_rect_in));
5720 TRACE("dst_rect_in %s\n", wine_dbgstr_rect(dst_rect_in));
5722 src_rect = *src_rect_in;
5723 dst_rect = *dst_rect_in;
5725 switch (filter) {
5726 case WINED3DTEXF_LINEAR:
5727 gl_filter = GL_LINEAR;
5728 break;
5730 default:
5731 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5732 case WINED3DTEXF_NONE:
5733 case WINED3DTEXF_POINT:
5734 gl_filter = GL_NEAREST;
5735 break;
5738 /* Make sure the drawables are up-to-date. Note that loading the
5739 * destination surface isn't strictly required if we overwrite the
5740 * entire surface. */
5741 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5742 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5744 if (!surface_is_offscreen((IWineD3DSurfaceImpl *)src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5745 else if (!surface_is_offscreen((IWineD3DSurfaceImpl *)dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5746 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5748 if (!context->valid)
5750 context_release(context);
5751 WARN("Invalid context, skipping blit.\n");
5752 return;
5755 gl_info = context->gl_info;
5757 if (!surface_is_offscreen((IWineD3DSurfaceImpl *)src_surface))
5759 GLenum buffer = surface_get_gl_buffer(src_surface);
5761 TRACE("Source surface %p is onscreen\n", src_surface);
5763 if(buffer == GL_FRONT) {
5764 RECT windowsize;
5765 UINT h;
5766 ClientToScreen(context->win_handle, &offset);
5767 GetClientRect(context->win_handle, &windowsize);
5768 h = windowsize.bottom - windowsize.top;
5769 src_rect.left -= offset.x; src_rect.right -=offset.x;
5770 src_rect.top = offset.y + h - src_rect.top;
5771 src_rect.bottom = offset.y + h - src_rect.bottom;
5772 } else {
5773 src_rect.top = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.top;
5774 src_rect.bottom = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect.bottom;
5777 ENTER_GL();
5778 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5779 glReadBuffer(buffer);
5780 checkGLcall("glReadBuffer()");
5781 } else {
5782 TRACE("Source surface %p is offscreen\n", src_surface);
5783 ENTER_GL();
5784 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5785 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)src_surface);
5786 glReadBuffer(GL_COLOR_ATTACHMENT0);
5787 checkGLcall("glReadBuffer()");
5788 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5790 LEAVE_GL();
5792 /* Attach dst surface to dst fbo */
5793 if (!surface_is_offscreen((IWineD3DSurfaceImpl *)dst_surface))
5795 GLenum buffer = surface_get_gl_buffer(dst_surface);
5797 TRACE("Destination surface %p is onscreen\n", dst_surface);
5799 if(buffer == GL_FRONT) {
5800 RECT windowsize;
5801 UINT h;
5802 ClientToScreen(context->win_handle, &offset);
5803 GetClientRect(context->win_handle, &windowsize);
5804 h = windowsize.bottom - windowsize.top;
5805 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5806 dst_rect.top = offset.y + h - dst_rect.top;
5807 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5808 } else {
5809 /* Screen coords = window coords, surface height = window height */
5810 dst_rect.top = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.top;
5811 dst_rect.bottom = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect.bottom;
5814 ENTER_GL();
5815 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5816 context_set_draw_buffer(context, buffer);
5818 else
5820 TRACE("Destination surface %p is offscreen\n", dst_surface);
5822 ENTER_GL();
5823 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5824 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)dst_surface);
5825 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5826 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5828 glDisable(GL_SCISSOR_TEST);
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5831 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5832 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5833 checkGLcall("glBlitFramebuffer()");
5835 LEAVE_GL();
5837 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5839 context_release(context);
5841 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5844 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5845 BOOL set_viewport) {
5846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5848 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5850 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5852 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5853 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5854 return WINED3DERR_INVALIDCALL;
5857 /* MSDN says that null disables the render target
5858 but a device must always be associated with a render target
5859 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5861 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5862 FIXME("Trying to set render target 0 to NULL\n");
5863 return WINED3DERR_INVALIDCALL;
5865 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5866 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);
5867 return WINED3DERR_INVALIDCALL;
5870 /* If we are trying to set what we already have, don't bother */
5871 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5872 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5873 return WINED3D_OK;
5875 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5876 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5877 This->render_targets[RenderTargetIndex] = pRenderTarget;
5879 /* Render target 0 is special */
5880 if(RenderTargetIndex == 0 && set_viewport) {
5881 /* Finally, reset the viewport and scissor rect as the MSDN states.
5882 * Tests show that stateblock recording is ignored, the change goes
5883 * directly into the primary stateblock.
5885 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5886 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5887 This->stateBlock->viewport.X = 0;
5888 This->stateBlock->viewport.Y = 0;
5889 This->stateBlock->viewport.MaxZ = 1.0f;
5890 This->stateBlock->viewport.MinZ = 0.0f;
5891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5893 This->stateBlock->scissorRect.top = 0;
5894 This->stateBlock->scissorRect.left = 0;
5895 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5896 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5899 return WINED3D_OK;
5902 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5904 HRESULT hr = WINED3D_OK;
5905 IWineD3DSurface *tmp;
5907 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5909 if (pNewZStencil == This->stencilBufferTarget) {
5910 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5911 } else {
5912 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5913 * depending on the renter target implementation being used.
5914 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5915 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5916 * stencil buffer and incur an extra memory overhead
5917 ******************************************************/
5919 if (This->stencilBufferTarget) {
5920 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5921 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5922 surface_modify_ds_location((IWineD3DSurfaceImpl *)This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5923 } else {
5924 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5925 surface_load_ds_location((IWineD3DSurfaceImpl *)This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5926 surface_modify_ds_location((IWineD3DSurfaceImpl *)This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5927 context_release(context);
5931 tmp = This->stencilBufferTarget;
5932 This->stencilBufferTarget = pNewZStencil;
5933 /* should we be calling the parent or the wined3d surface? */
5934 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5935 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5936 hr = WINED3D_OK;
5938 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5939 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5946 return hr;
5949 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5950 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5952 /* TODO: the use of Impl is deprecated. */
5953 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5954 WINED3DLOCKED_RECT lockedRect;
5956 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5958 /* some basic validation checks */
5959 if(This->cursorTexture) {
5960 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5961 ENTER_GL();
5962 glDeleteTextures(1, &This->cursorTexture);
5963 LEAVE_GL();
5964 context_release(context);
5965 This->cursorTexture = 0;
5968 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5969 This->haveHardwareCursor = TRUE;
5970 else
5971 This->haveHardwareCursor = FALSE;
5973 if(pCursorBitmap) {
5974 WINED3DLOCKED_RECT rect;
5976 /* MSDN: Cursor must be A8R8G8B8 */
5977 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5979 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5980 return WINED3DERR_INVALIDCALL;
5983 /* MSDN: Cursor must be smaller than the display mode */
5984 if(pSur->currentDesc.Width > This->ddraw_width ||
5985 pSur->currentDesc.Height > This->ddraw_height) {
5986 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);
5987 return WINED3DERR_INVALIDCALL;
5990 if (!This->haveHardwareCursor) {
5991 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5993 /* Do not store the surface's pointer because the application may
5994 * release it after setting the cursor image. Windows doesn't
5995 * addref the set surface, so we can't do this either without
5996 * creating circular refcount dependencies. Copy out the gl texture
5997 * instead.
5999 This->cursorWidth = pSur->currentDesc.Width;
6000 This->cursorHeight = pSur->currentDesc.Height;
6001 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6003 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6004 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6005 struct wined3d_context *context;
6006 char *mem, *bits = rect.pBits;
6007 GLint intfmt = format_desc->glInternal;
6008 GLint format = format_desc->glFormat;
6009 GLint type = format_desc->glType;
6010 INT height = This->cursorHeight;
6011 INT width = This->cursorWidth;
6012 INT bpp = format_desc->byte_count;
6013 DWORD sampler;
6014 INT i;
6016 /* Reformat the texture memory (pitch and width can be
6017 * different) */
6018 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6019 for(i = 0; i < height; i++)
6020 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6021 IWineD3DSurface_UnlockRect(pCursorBitmap);
6023 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6025 ENTER_GL();
6027 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6029 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6030 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6033 /* Make sure that a proper texture unit is selected */
6034 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6035 checkGLcall("glActiveTextureARB");
6036 sampler = This->rev_tex_unit_map[0];
6037 if (sampler != WINED3D_UNMAPPED_STAGE)
6039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6041 /* Create a new cursor texture */
6042 glGenTextures(1, &This->cursorTexture);
6043 checkGLcall("glGenTextures");
6044 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6045 checkGLcall("glBindTexture");
6046 /* Copy the bitmap memory into the cursor texture */
6047 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6048 HeapFree(GetProcessHeap(), 0, mem);
6049 checkGLcall("glTexImage2D");
6051 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6053 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6054 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6057 LEAVE_GL();
6059 context_release(context);
6061 else
6063 FIXME("A cursor texture was not returned.\n");
6064 This->cursorTexture = 0;
6067 else
6069 /* Draw a hardware cursor */
6070 ICONINFO cursorInfo;
6071 HCURSOR cursor;
6072 /* Create and clear maskBits because it is not needed for
6073 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6074 * chunks. */
6075 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6076 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6077 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6078 WINED3DLOCK_NO_DIRTY_UPDATE |
6079 WINED3DLOCK_READONLY
6081 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6082 pSur->currentDesc.Height);
6084 cursorInfo.fIcon = FALSE;
6085 cursorInfo.xHotspot = XHotSpot;
6086 cursorInfo.yHotspot = YHotSpot;
6087 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6088 1, 1, maskBits);
6089 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6090 1, 32, lockedRect.pBits);
6091 IWineD3DSurface_UnlockRect(pCursorBitmap);
6092 /* Create our cursor and clean up. */
6093 cursor = CreateIconIndirect(&cursorInfo);
6094 SetCursor(cursor);
6095 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6096 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6097 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6098 This->hardwareCursor = cursor;
6099 HeapFree(GetProcessHeap(), 0, maskBits);
6103 This->xHotSpot = XHotSpot;
6104 This->yHotSpot = YHotSpot;
6105 return WINED3D_OK;
6108 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6110 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6112 This->xScreenSpace = XScreenSpace;
6113 This->yScreenSpace = YScreenSpace;
6115 return;
6119 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6121 BOOL oldVisible = This->bCursorVisible;
6122 POINT pt;
6124 TRACE("(%p) : visible(%d)\n", This, bShow);
6127 * When ShowCursor is first called it should make the cursor appear at the OS's last
6128 * known cursor position. Because of this, some applications just repetitively call
6129 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6131 GetCursorPos(&pt);
6132 This->xScreenSpace = pt.x;
6133 This->yScreenSpace = pt.y;
6135 if (This->haveHardwareCursor) {
6136 This->bCursorVisible = bShow;
6137 if (bShow)
6138 SetCursor(This->hardwareCursor);
6139 else
6140 SetCursor(NULL);
6142 else
6144 if (This->cursorTexture)
6145 This->bCursorVisible = bShow;
6148 return oldVisible;
6151 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6152 TRACE("checking resource %p for eviction\n", resource);
6153 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6154 TRACE("Evicting %p\n", resource);
6155 IWineD3DResource_UnLoad(resource);
6157 IWineD3DResource_Release(resource);
6158 return S_OK;
6161 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6163 TRACE("iface %p.\n", iface);
6165 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6166 return WINED3D_OK;
6169 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6171 IWineD3DDeviceImpl *device = surface->resource.device;
6172 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6174 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6175 if(surface->Flags & SFLAG_DIBSECTION) {
6176 /* Release the DC */
6177 SelectObject(surface->hDC, surface->dib.holdbitmap);
6178 DeleteDC(surface->hDC);
6179 /* Release the DIB section */
6180 DeleteObject(surface->dib.DIBsection);
6181 surface->dib.bitmap_data = NULL;
6182 surface->resource.allocatedMemory = NULL;
6183 surface->Flags &= ~SFLAG_DIBSECTION;
6185 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6186 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6187 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6188 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6190 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6191 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6192 } else {
6193 surface->pow2Width = surface->pow2Height = 1;
6194 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6195 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6198 if (surface->texture_name)
6200 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6201 ENTER_GL();
6202 glDeleteTextures(1, &surface->texture_name);
6203 LEAVE_GL();
6204 context_release(context);
6205 surface->texture_name = 0;
6206 surface->Flags &= ~SFLAG_CLIENT;
6208 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6209 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6210 surface->Flags |= SFLAG_NONPOW2;
6211 } else {
6212 surface->Flags &= ~SFLAG_NONPOW2;
6214 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6215 surface->resource.allocatedMemory = NULL;
6216 surface->resource.heapMemory = NULL;
6217 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6219 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6220 * to a FBO */
6221 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6223 return E_OUTOFMEMORY;
6225 return WINED3D_OK;
6228 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6229 TRACE("Unloading resource %p\n", resource);
6230 IWineD3DResource_UnLoad(resource);
6231 IWineD3DResource_Release(resource);
6232 return S_OK;
6235 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6237 UINT i, count;
6238 WINED3DDISPLAYMODE m;
6239 HRESULT hr;
6241 /* All Windowed modes are supported, as is leaving the current mode */
6242 if(pp->Windowed) return TRUE;
6243 if(!pp->BackBufferWidth) return TRUE;
6244 if(!pp->BackBufferHeight) return TRUE;
6246 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6247 for(i = 0; i < count; i++) {
6248 memset(&m, 0, sizeof(m));
6249 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6250 if(FAILED(hr)) {
6251 ERR("EnumAdapterModes failed\n");
6253 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6254 /* Mode found, it is supported */
6255 return TRUE;
6258 /* Mode not found -> not supported */
6259 return FALSE;
6262 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6265 const struct wined3d_gl_info *gl_info;
6266 struct wined3d_context *context;
6267 IWineD3DBaseShaderImpl *shader;
6269 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6270 gl_info = context->gl_info;
6272 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6273 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6274 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6277 ENTER_GL();
6278 if(This->depth_blt_texture) {
6279 glDeleteTextures(1, &This->depth_blt_texture);
6280 This->depth_blt_texture = 0;
6282 if (This->depth_blt_rb) {
6283 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6284 This->depth_blt_rb = 0;
6285 This->depth_blt_rb_w = 0;
6286 This->depth_blt_rb_h = 0;
6288 LEAVE_GL();
6290 This->blitter->free_private(iface);
6291 This->frag_pipe->free_private(iface);
6292 This->shader_backend->shader_free_private(iface);
6293 destroy_dummy_textures(This, gl_info);
6295 context_release(context);
6297 while (This->numContexts)
6299 context_destroy(This, This->contexts[0]);
6301 HeapFree(GetProcessHeap(), 0, swapchain->context);
6302 swapchain->context = NULL;
6303 swapchain->num_contexts = 0;
6306 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6309 struct wined3d_context *context;
6310 HRESULT hr;
6311 IWineD3DSurfaceImpl *target;
6313 /* Recreate the primary swapchain's context */
6314 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6315 if (!swapchain->context)
6317 ERR("Failed to allocate memory for swapchain context array.\n");
6318 return E_OUTOFMEMORY;
6321 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6322 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6324 WARN("Failed to create context.\n");
6325 HeapFree(GetProcessHeap(), 0, swapchain->context);
6326 return E_FAIL;
6329 swapchain->context[0] = context;
6330 swapchain->num_contexts = 1;
6331 create_dummy_textures(This);
6332 context_release(context);
6334 hr = This->shader_backend->shader_alloc_private(iface);
6335 if (FAILED(hr))
6337 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6338 goto err;
6341 hr = This->frag_pipe->alloc_private(iface);
6342 if (FAILED(hr))
6344 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6345 This->shader_backend->shader_free_private(iface);
6346 goto err;
6349 hr = This->blitter->alloc_private(iface);
6350 if (FAILED(hr))
6352 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6353 This->frag_pipe->free_private(iface);
6354 This->shader_backend->shader_free_private(iface);
6355 goto err;
6358 return WINED3D_OK;
6360 err:
6361 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6362 destroy_dummy_textures(This, context->gl_info);
6363 context_release(context);
6364 context_destroy(This, context);
6365 HeapFree(GetProcessHeap(), 0, swapchain->context);
6366 swapchain->num_contexts = 0;
6367 return hr;
6370 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6372 IWineD3DSwapChainImpl *swapchain;
6373 HRESULT hr;
6374 BOOL DisplayModeChanged = FALSE;
6375 WINED3DDISPLAYMODE mode;
6376 TRACE("(%p)\n", This);
6378 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6379 if(FAILED(hr)) {
6380 ERR("Failed to get the first implicit swapchain\n");
6381 return hr;
6384 if(!is_display_mode_supported(This, pPresentationParameters)) {
6385 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6386 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6387 pPresentationParameters->BackBufferHeight);
6388 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6389 return WINED3DERR_INVALIDCALL;
6392 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6393 * on an existing gl context, so there's no real need for recreation.
6395 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6397 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6399 TRACE("New params:\n");
6400 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6401 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6402 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6403 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6404 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6405 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6406 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6407 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6408 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6409 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6410 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6411 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6412 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6414 /* No special treatment of these parameters. Just store them */
6415 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6416 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6417 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6418 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6420 /* What to do about these? */
6421 if(pPresentationParameters->BackBufferCount != 0 &&
6422 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6423 ERR("Cannot change the back buffer count yet\n");
6425 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6426 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6427 ERR("Cannot change the back buffer format yet\n");
6429 if(pPresentationParameters->hDeviceWindow != NULL &&
6430 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6431 ERR("Cannot change the device window yet\n");
6433 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6434 HRESULT hrc;
6436 TRACE("Creating the depth stencil buffer\n");
6438 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6439 This->parent,
6440 pPresentationParameters->BackBufferWidth,
6441 pPresentationParameters->BackBufferHeight,
6442 pPresentationParameters->AutoDepthStencilFormat,
6443 pPresentationParameters->MultiSampleType,
6444 pPresentationParameters->MultiSampleQuality,
6445 FALSE,
6446 &This->auto_depth_stencil_buffer);
6448 if (FAILED(hrc)) {
6449 ERR("Failed to create the depth stencil buffer\n");
6450 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6451 return WINED3DERR_INVALIDCALL;
6455 /* Reset the depth stencil */
6456 if (pPresentationParameters->EnableAutoDepthStencil)
6457 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6458 else
6459 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6461 TRACE("Resetting stateblock\n");
6462 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6463 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6465 delete_opengl_contexts(iface, swapchain);
6467 if(pPresentationParameters->Windowed) {
6468 mode.Width = swapchain->orig_width;
6469 mode.Height = swapchain->orig_height;
6470 mode.RefreshRate = 0;
6471 mode.Format = swapchain->presentParms.BackBufferFormat;
6472 } else {
6473 mode.Width = pPresentationParameters->BackBufferWidth;
6474 mode.Height = pPresentationParameters->BackBufferHeight;
6475 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6476 mode.Format = swapchain->presentParms.BackBufferFormat;
6479 /* Should Width == 800 && Height == 0 set 800x600? */
6480 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6481 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6482 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6484 UINT i;
6486 if(!pPresentationParameters->Windowed) {
6487 DisplayModeChanged = TRUE;
6489 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6490 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6492 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6493 if(FAILED(hr))
6495 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6496 return hr;
6499 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6500 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6501 if(FAILED(hr))
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6504 return hr;
6507 if(This->auto_depth_stencil_buffer) {
6508 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6509 if(FAILED(hr))
6511 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6512 return hr;
6517 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6518 || DisplayModeChanged)
6520 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6522 if (!pPresentationParameters->Windowed)
6524 if(swapchain->presentParms.Windowed) {
6525 /* switch from windowed to fs */
6526 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6527 pPresentationParameters->BackBufferHeight);
6528 } else {
6529 /* Fullscreen -> fullscreen mode change */
6530 MoveWindow(swapchain->device_window, 0, 0,
6531 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6532 TRUE);
6535 else if (!swapchain->presentParms.Windowed)
6537 /* Fullscreen -> windowed switch */
6538 swapchain_restore_fullscreen_window(swapchain);
6540 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6541 } else if(!pPresentationParameters->Windowed) {
6542 DWORD style = This->style, exStyle = This->exStyle;
6543 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6544 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6545 * Reset to clear up their mess. Guild Wars also loses the device during that.
6547 This->style = 0;
6548 This->exStyle = 0;
6549 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6550 pPresentationParameters->BackBufferHeight);
6551 This->style = style;
6552 This->exStyle = exStyle;
6555 /* Note: No parent needed for initial internal stateblock */
6556 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6557 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6558 else TRACE("Created stateblock %p\n", This->stateBlock);
6559 This->updateStateBlock = This->stateBlock;
6560 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6562 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6563 if(FAILED(hr)) {
6564 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6567 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6569 RECT client_rect;
6570 GetClientRect(swapchain->win_handle, &client_rect);
6572 if(!swapchain->presentParms.BackBufferCount)
6574 TRACE("Single buffered rendering\n");
6575 swapchain->render_to_fbo = FALSE;
6577 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6578 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6580 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6581 swapchain->presentParms.BackBufferWidth,
6582 swapchain->presentParms.BackBufferHeight,
6583 client_rect.right, client_rect.bottom);
6584 swapchain->render_to_fbo = TRUE;
6586 else
6588 TRACE("Rendering directly to GL_BACK\n");
6589 swapchain->render_to_fbo = FALSE;
6593 hr = create_primary_opengl_context(iface, swapchain);
6594 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6596 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6597 * first use
6599 return hr;
6602 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6604 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6606 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6608 return WINED3D_OK;
6612 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6614 TRACE("(%p) : pParameters %p\n", This, pParameters);
6616 *pParameters = This->createParms;
6617 return WINED3D_OK;
6620 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6621 IWineD3DSwapChain *swapchain;
6623 TRACE("Relaying to swapchain\n");
6625 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6626 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6627 IWineD3DSwapChain_Release(swapchain);
6631 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6632 IWineD3DSwapChain *swapchain;
6634 TRACE("Relaying to swapchain\n");
6636 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6637 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6638 IWineD3DSwapChain_Release(swapchain);
6643 /** ********************************************************
6644 * Notification functions
6645 ** ********************************************************/
6646 /** This function must be called in the release of a resource when ref == 0,
6647 * the contents of resource must still be correct,
6648 * any handles to other resource held by the caller must be closed
6649 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6650 *****************************************************/
6651 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6653 TRACE("(%p) : Adding resource %p\n", This, resource);
6655 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6658 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6660 TRACE("(%p) : Removing resource %p\n", This, resource);
6662 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6665 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6667 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6668 int counter;
6670 TRACE("(%p) : resource %p\n", This, resource);
6672 context_resource_released((IWineD3DDevice *)This, resource, type);
6674 switch (type) {
6675 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6676 case WINED3DRTYPE_SURFACE: {
6677 unsigned int i;
6679 if (This->d3d_initialized)
6681 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6683 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6684 This->render_targets[i] = NULL;
6687 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6688 This->stencilBufferTarget = NULL;
6692 break;
6694 case WINED3DRTYPE_TEXTURE:
6695 case WINED3DRTYPE_CUBETEXTURE:
6696 case WINED3DRTYPE_VOLUMETEXTURE:
6697 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6698 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6699 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6700 This->stateBlock->textures[counter] = NULL;
6702 if (This->updateStateBlock != This->stateBlock ){
6703 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6704 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6705 This->updateStateBlock->textures[counter] = NULL;
6709 break;
6710 case WINED3DRTYPE_VOLUME:
6711 /* TODO: nothing really? */
6712 break;
6713 case WINED3DRTYPE_BUFFER:
6715 int streamNumber;
6716 TRACE("Cleaning up stream pointers\n");
6718 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6719 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6720 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6722 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6723 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6724 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6725 This->updateStateBlock->streamSource[streamNumber] = 0;
6726 /* Set changed flag? */
6729 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) */
6730 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6731 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6732 This->stateBlock->streamSource[streamNumber] = 0;
6737 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6738 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6739 This->updateStateBlock->pIndexData = NULL;
6742 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6743 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6744 This->stateBlock->pIndexData = NULL;
6748 break;
6750 default:
6751 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6752 break;
6756 /* Remove the resource from the resourceStore */
6757 device_resource_remove(This, resource);
6759 TRACE("Resource released\n");
6763 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6765 IWineD3DResourceImpl *resource, *cursor;
6766 HRESULT ret;
6767 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6769 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6770 TRACE("enumerating resource %p\n", resource);
6771 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6772 ret = pCallback((IWineD3DResource *) resource, pData);
6773 if(ret == S_FALSE) {
6774 TRACE("Canceling enumeration\n");
6775 break;
6778 return WINED3D_OK;
6781 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 IWineD3DResourceImpl *resource;
6786 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6788 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6789 if (type == WINED3DRTYPE_SURFACE)
6791 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6793 TRACE("Found surface %p for dc %p.\n", resource, dc);
6794 *surface = (IWineD3DSurface *)resource;
6795 return WINED3D_OK;
6800 return WINED3DERR_INVALIDCALL;
6803 /**********************************************************
6804 * IWineD3DDevice VTbl follows
6805 **********************************************************/
6807 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6809 /*** IUnknown methods ***/
6810 IWineD3DDeviceImpl_QueryInterface,
6811 IWineD3DDeviceImpl_AddRef,
6812 IWineD3DDeviceImpl_Release,
6813 /*** IWineD3DDevice methods ***/
6814 IWineD3DDeviceImpl_GetParent,
6815 /*** Creation methods**/
6816 IWineD3DDeviceImpl_CreateBuffer,
6817 IWineD3DDeviceImpl_CreateVertexBuffer,
6818 IWineD3DDeviceImpl_CreateIndexBuffer,
6819 IWineD3DDeviceImpl_CreateStateBlock,
6820 IWineD3DDeviceImpl_CreateSurface,
6821 IWineD3DDeviceImpl_CreateRendertargetView,
6822 IWineD3DDeviceImpl_CreateTexture,
6823 IWineD3DDeviceImpl_CreateVolumeTexture,
6824 IWineD3DDeviceImpl_CreateVolume,
6825 IWineD3DDeviceImpl_CreateCubeTexture,
6826 IWineD3DDeviceImpl_CreateQuery,
6827 IWineD3DDeviceImpl_CreateSwapChain,
6828 IWineD3DDeviceImpl_CreateVertexDeclaration,
6829 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6830 IWineD3DDeviceImpl_CreateVertexShader,
6831 IWineD3DDeviceImpl_CreateGeometryShader,
6832 IWineD3DDeviceImpl_CreatePixelShader,
6833 IWineD3DDeviceImpl_CreatePalette,
6834 /*** Odd functions **/
6835 IWineD3DDeviceImpl_Init3D,
6836 IWineD3DDeviceImpl_InitGDI,
6837 IWineD3DDeviceImpl_Uninit3D,
6838 IWineD3DDeviceImpl_UninitGDI,
6839 IWineD3DDeviceImpl_SetMultithreaded,
6840 IWineD3DDeviceImpl_EvictManagedResources,
6841 IWineD3DDeviceImpl_GetAvailableTextureMem,
6842 IWineD3DDeviceImpl_GetBackBuffer,
6843 IWineD3DDeviceImpl_GetCreationParameters,
6844 IWineD3DDeviceImpl_GetDeviceCaps,
6845 IWineD3DDeviceImpl_GetDirect3D,
6846 IWineD3DDeviceImpl_GetDisplayMode,
6847 IWineD3DDeviceImpl_SetDisplayMode,
6848 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6849 IWineD3DDeviceImpl_GetRasterStatus,
6850 IWineD3DDeviceImpl_GetSwapChain,
6851 IWineD3DDeviceImpl_Reset,
6852 IWineD3DDeviceImpl_SetDialogBoxMode,
6853 IWineD3DDeviceImpl_SetCursorProperties,
6854 IWineD3DDeviceImpl_SetCursorPosition,
6855 IWineD3DDeviceImpl_ShowCursor,
6856 /*** Getters and setters **/
6857 IWineD3DDeviceImpl_SetClipPlane,
6858 IWineD3DDeviceImpl_GetClipPlane,
6859 IWineD3DDeviceImpl_SetClipStatus,
6860 IWineD3DDeviceImpl_GetClipStatus,
6861 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6862 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6863 IWineD3DDeviceImpl_SetDepthStencilSurface,
6864 IWineD3DDeviceImpl_GetDepthStencilSurface,
6865 IWineD3DDeviceImpl_SetGammaRamp,
6866 IWineD3DDeviceImpl_GetGammaRamp,
6867 IWineD3DDeviceImpl_SetIndexBuffer,
6868 IWineD3DDeviceImpl_GetIndexBuffer,
6869 IWineD3DDeviceImpl_SetBaseVertexIndex,
6870 IWineD3DDeviceImpl_GetBaseVertexIndex,
6871 IWineD3DDeviceImpl_SetLight,
6872 IWineD3DDeviceImpl_GetLight,
6873 IWineD3DDeviceImpl_SetLightEnable,
6874 IWineD3DDeviceImpl_GetLightEnable,
6875 IWineD3DDeviceImpl_SetMaterial,
6876 IWineD3DDeviceImpl_GetMaterial,
6877 IWineD3DDeviceImpl_SetNPatchMode,
6878 IWineD3DDeviceImpl_GetNPatchMode,
6879 IWineD3DDeviceImpl_SetPaletteEntries,
6880 IWineD3DDeviceImpl_GetPaletteEntries,
6881 IWineD3DDeviceImpl_SetPixelShader,
6882 IWineD3DDeviceImpl_GetPixelShader,
6883 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6884 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6885 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6886 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6887 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6888 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6889 IWineD3DDeviceImpl_SetRenderState,
6890 IWineD3DDeviceImpl_GetRenderState,
6891 IWineD3DDeviceImpl_SetRenderTarget,
6892 IWineD3DDeviceImpl_GetRenderTarget,
6893 IWineD3DDeviceImpl_SetFrontBackBuffers,
6894 IWineD3DDeviceImpl_SetSamplerState,
6895 IWineD3DDeviceImpl_GetSamplerState,
6896 IWineD3DDeviceImpl_SetScissorRect,
6897 IWineD3DDeviceImpl_GetScissorRect,
6898 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6899 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6900 IWineD3DDeviceImpl_SetStreamSource,
6901 IWineD3DDeviceImpl_GetStreamSource,
6902 IWineD3DDeviceImpl_SetStreamSourceFreq,
6903 IWineD3DDeviceImpl_GetStreamSourceFreq,
6904 IWineD3DDeviceImpl_SetTexture,
6905 IWineD3DDeviceImpl_GetTexture,
6906 IWineD3DDeviceImpl_SetTextureStageState,
6907 IWineD3DDeviceImpl_GetTextureStageState,
6908 IWineD3DDeviceImpl_SetTransform,
6909 IWineD3DDeviceImpl_GetTransform,
6910 IWineD3DDeviceImpl_SetVertexDeclaration,
6911 IWineD3DDeviceImpl_GetVertexDeclaration,
6912 IWineD3DDeviceImpl_SetVertexShader,
6913 IWineD3DDeviceImpl_GetVertexShader,
6914 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6915 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6916 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6917 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6918 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6919 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6920 IWineD3DDeviceImpl_SetViewport,
6921 IWineD3DDeviceImpl_GetViewport,
6922 IWineD3DDeviceImpl_MultiplyTransform,
6923 IWineD3DDeviceImpl_ValidateDevice,
6924 IWineD3DDeviceImpl_ProcessVertices,
6925 /*** State block ***/
6926 IWineD3DDeviceImpl_BeginStateBlock,
6927 IWineD3DDeviceImpl_EndStateBlock,
6928 /*** Scene management ***/
6929 IWineD3DDeviceImpl_BeginScene,
6930 IWineD3DDeviceImpl_EndScene,
6931 IWineD3DDeviceImpl_Present,
6932 IWineD3DDeviceImpl_Clear,
6933 IWineD3DDeviceImpl_ClearRendertargetView,
6934 /*** Drawing ***/
6935 IWineD3DDeviceImpl_SetPrimitiveType,
6936 IWineD3DDeviceImpl_GetPrimitiveType,
6937 IWineD3DDeviceImpl_DrawPrimitive,
6938 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6939 IWineD3DDeviceImpl_DrawPrimitiveUP,
6940 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6941 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6942 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6943 IWineD3DDeviceImpl_DrawRectPatch,
6944 IWineD3DDeviceImpl_DrawTriPatch,
6945 IWineD3DDeviceImpl_DeletePatch,
6946 IWineD3DDeviceImpl_ColorFill,
6947 IWineD3DDeviceImpl_UpdateTexture,
6948 IWineD3DDeviceImpl_UpdateSurface,
6949 IWineD3DDeviceImpl_GetFrontBufferData,
6950 /*** object tracking ***/
6951 IWineD3DDeviceImpl_EnumResources,
6952 IWineD3DDeviceImpl_GetSurfaceFromDC,
6953 IWineD3DDeviceImpl_AcquireFocusWindow,
6954 IWineD3DDeviceImpl_ReleaseFocusWindow,
6957 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6958 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6959 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6961 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6962 const struct fragment_pipeline *fragment_pipeline;
6963 struct shader_caps shader_caps;
6964 struct fragment_caps ffp_caps;
6965 WINED3DDISPLAYMODE mode;
6966 unsigned int i;
6967 HRESULT hr;
6969 device->lpVtbl = &IWineD3DDevice_Vtbl;
6970 device->ref = 1;
6971 device->wined3d = (IWineD3D *)wined3d;
6972 IWineD3D_AddRef(device->wined3d);
6973 device->adapter = wined3d->adapter_count ? adapter : NULL;
6974 device->parent = parent;
6975 device->device_parent = device_parent;
6976 list_init(&device->resources);
6977 list_init(&device->shaders);
6979 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6980 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6982 /* Get the initial screen setup for ddraw. */
6983 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6984 if (FAILED(hr))
6986 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6987 IWineD3D_Release(device->wined3d);
6988 return hr;
6990 device->ddraw_width = mode.Width;
6991 device->ddraw_height = mode.Height;
6992 device->ddraw_format = mode.Format;
6994 /* Save the creation parameters. */
6995 device->createParms.AdapterOrdinal = adapter_idx;
6996 device->createParms.DeviceType = device_type;
6997 device->createParms.hFocusWindow = focus_window;
6998 device->createParms.BehaviorFlags = flags;
7000 device->devType = device_type;
7001 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7003 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7004 device->shader_backend = adapter->shader_backend;
7006 memset(&shader_caps, 0, sizeof(shader_caps));
7007 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7008 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7009 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7010 device->vs_clipping = shader_caps.VSClipping;
7012 memset(&ffp_caps, 0, sizeof(ffp_caps));
7013 fragment_pipeline = adapter->fragment_pipe;
7014 device->frag_pipe = fragment_pipeline;
7015 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7016 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7018 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7019 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7020 if (FAILED(hr))
7022 ERR("Failed to compile state table, hr %#x.\n", hr);
7023 IWineD3D_Release(device->wined3d);
7024 return hr;
7027 device->blitter = adapter->blitter;
7029 return WINED3D_OK;
7033 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7034 DWORD rep = This->StateTable[state].representative;
7035 struct wined3d_context *context;
7036 DWORD idx;
7037 BYTE shift;
7038 UINT i;
7040 for(i = 0; i < This->numContexts; i++) {
7041 context = This->contexts[i];
7042 if(isStateDirty(context, rep)) continue;
7044 context->dirtyArray[context->numDirtyEntries++] = rep;
7045 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7046 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7047 context->isStateDirty[idx] |= (1 << shift);
7051 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7053 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7054 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7055 *width = surface->pow2Width;
7056 *height = surface->pow2Height;
7059 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7061 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7062 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7063 * current context's drawable, which is the size of the back buffer of the swapchain
7064 * the active context belongs to. */
7065 *width = swapchain->presentParms.BackBufferWidth;
7066 *height = swapchain->presentParms.BackBufferHeight;
7069 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7070 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7072 if (device->filter_messages)
7074 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7075 window, message, wparam, lparam);
7076 return DefWindowProcW(window, message, wparam, lparam);
7079 if (message == WM_DESTROY)
7081 TRACE("unregister window %p.\n", window);
7082 wined3d_unregister_window(window);
7084 if (device->focus_window == window) device->focus_window = NULL;
7085 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7088 return CallWindowProcW(proc, window, message, wparam, lparam);