wined3d: Simply pass implementation pointers to stretch_rect_fbo().
[wine.git] / dlls / wined3d / device.c
blobc2e0511a11a6070b4a69c42b2bd3b0b7d1a263b5
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;
566 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
567 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
569 if (device->onscreen_depth_stencil)
571 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
572 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN);
573 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
575 device->onscreen_depth_stencil = depth_stencil;
576 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
579 /**********************************************************
580 * IUnknown parts follows
581 **********************************************************/
583 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
588 if (IsEqualGUID(riid, &IID_IUnknown)
589 || IsEqualGUID(riid, &IID_IWineD3DBase)
590 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
591 IUnknown_AddRef(iface);
592 *ppobj = This;
593 return S_OK;
595 *ppobj = NULL;
596 return E_NOINTERFACE;
599 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 ULONG refCount = InterlockedIncrement(&This->ref);
603 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
604 return refCount;
607 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
609 ULONG refCount = InterlockedDecrement(&This->ref);
611 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
613 if (!refCount) {
614 UINT i;
616 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
617 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
618 This->multistate_funcs[i] = NULL;
621 /* TODO: Clean up all the surfaces and textures! */
622 /* NOTE: You must release the parent if the object was created via a callback
623 ** ***************************/
625 if (!list_empty(&This->resources))
627 IWineD3DResourceImpl *resource;
628 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
630 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
632 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
633 FIXME("Leftover resource %p with type %s (%#x).\n",
634 resource, debug_d3dresourcetype(type), type);
638 if(This->contexts) ERR("Context array not freed!\n");
639 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
640 This->haveHardwareCursor = FALSE;
642 IWineD3D_Release(This->wined3d);
643 This->wined3d = NULL;
644 HeapFree(GetProcessHeap(), 0, This);
645 TRACE("Freed device %p\n", This);
646 This = NULL;
648 return refCount;
651 /**********************************************************
652 * IWineD3DDevice implementation follows
653 **********************************************************/
654 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
656 *pParent = This->parent;
657 IUnknown_AddRef(This->parent);
658 return WINED3D_OK;
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
662 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
665 struct wined3d_buffer *object;
666 HRESULT hr;
668 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
670 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
671 if (!object)
673 ERR("Failed to allocate memory\n");
674 return E_OUTOFMEMORY;
677 FIXME("Ignoring access flags (pool)\n");
679 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
680 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
681 if (FAILED(hr))
683 WARN("Failed to initialize buffer, hr %#x.\n", hr);
684 HeapFree(GetProcessHeap(), 0, object);
685 return hr;
687 object->desc = *desc;
689 TRACE("Created buffer %p.\n", object);
691 *buffer = (IWineD3DBuffer *)object;
693 return WINED3D_OK;
696 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
697 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
698 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
701 struct wined3d_buffer *object;
702 HRESULT hr;
704 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
705 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
707 if (Pool == WINED3DPOOL_SCRATCH)
709 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
710 * anyway, SCRATCH vertex buffers aren't usable anywhere
712 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
713 *ppVertexBuffer = NULL;
714 return WINED3DERR_INVALIDCALL;
717 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
718 if (!object)
720 ERR("Out of memory\n");
721 *ppVertexBuffer = NULL;
722 return WINED3DERR_OUTOFVIDEOMEMORY;
725 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
726 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
727 if (FAILED(hr))
729 WARN("Failed to initialize buffer, hr %#x.\n", hr);
730 HeapFree(GetProcessHeap(), 0, object);
731 return hr;
734 TRACE("Created buffer %p.\n", object);
735 *ppVertexBuffer = (IWineD3DBuffer *)object;
737 return WINED3D_OK;
740 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
741 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
742 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
745 struct wined3d_buffer *object;
746 HRESULT hr;
748 TRACE("(%p) Creating index buffer\n", This);
750 /* Allocate the storage for the device */
751 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
752 if (!object)
754 ERR("Out of memory\n");
755 *ppIndexBuffer = NULL;
756 return WINED3DERR_OUTOFVIDEOMEMORY;
759 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
760 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
761 parent, parent_ops);
762 if (FAILED(hr))
764 WARN("Failed to initialize buffer, hr %#x\n", hr);
765 HeapFree(GetProcessHeap(), 0, object);
766 return hr;
769 TRACE("Created buffer %p.\n", object);
771 *ppIndexBuffer = (IWineD3DBuffer *) object;
773 return WINED3D_OK;
776 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
777 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
780 IWineD3DStateBlockImpl *object;
781 HRESULT hr;
783 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
784 if(!object)
786 ERR("Failed to allocate stateblock memory.\n");
787 return E_OUTOFMEMORY;
790 hr = stateblock_init(object, This, type);
791 if (FAILED(hr))
793 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
794 HeapFree(GetProcessHeap(), 0, object);
795 return hr;
798 TRACE("Created stateblock %p.\n", object);
799 *stateblock = (IWineD3DStateBlock *)object;
801 return WINED3D_OK;
804 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
805 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
806 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
807 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
810 IWineD3DSurfaceImpl *object;
811 HRESULT hr;
813 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
814 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
815 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
816 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
817 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
819 if (Impl == SURFACE_OPENGL && !This->adapter)
821 ERR("OpenGL surfaces are not available without OpenGL.\n");
822 return WINED3DERR_NOTAVAILABLE;
825 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
826 if (!object)
828 ERR("Failed to allocate surface memory.\n");
829 return WINED3DERR_OUTOFVIDEOMEMORY;
832 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
833 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
834 if (FAILED(hr))
836 WARN("Failed to initialize surface, returning %#x.\n", hr);
837 HeapFree(GetProcessHeap(), 0, object);
838 return hr;
841 TRACE("(%p) : Created surface %p\n", This, object);
843 *ppSurface = (IWineD3DSurface *)object;
845 return hr;
848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
849 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
851 struct wined3d_rendertarget_view *object;
853 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
854 iface, resource, parent, rendertarget_view);
856 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
857 if (!object)
859 ERR("Failed to allocate memory\n");
860 return E_OUTOFMEMORY;
863 wined3d_rendertarget_view_init(object, resource, parent);
865 TRACE("Created render target view %p.\n", object);
866 *rendertarget_view = (IWineD3DRendertargetView *)object;
868 return WINED3D_OK;
871 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
872 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
873 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
876 IWineD3DTextureImpl *object;
877 HRESULT hr;
879 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
880 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
881 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
883 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
884 if (!object)
886 ERR("Out of memory\n");
887 *ppTexture = NULL;
888 return WINED3DERR_OUTOFVIDEOMEMORY;
891 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
892 if (FAILED(hr))
894 WARN("Failed to initialize texture, returning %#x\n", hr);
895 HeapFree(GetProcessHeap(), 0, object);
896 *ppTexture = NULL;
897 return hr;
900 *ppTexture = (IWineD3DTexture *)object;
902 TRACE("(%p) : Created texture %p\n", This, object);
904 return WINED3D_OK;
907 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
908 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
909 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DVolumeTextureImpl *object;
913 HRESULT hr;
915 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
916 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
918 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
919 if (!object)
921 ERR("Out of memory\n");
922 *ppVolumeTexture = NULL;
923 return WINED3DERR_OUTOFVIDEOMEMORY;
926 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
927 if (FAILED(hr))
929 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
930 HeapFree(GetProcessHeap(), 0, object);
931 *ppVolumeTexture = NULL;
932 return hr;
935 TRACE("(%p) : Created volume texture %p.\n", This, object);
936 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
938 return WINED3D_OK;
941 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
942 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
943 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
946 IWineD3DVolumeImpl *object;
947 HRESULT hr;
949 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
950 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
952 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
953 if (!object)
955 ERR("Out of memory\n");
956 *ppVolume = NULL;
957 return WINED3DERR_OUTOFVIDEOMEMORY;
960 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
961 if (FAILED(hr))
963 WARN("Failed to initialize volume, returning %#x.\n", hr);
964 HeapFree(GetProcessHeap(), 0, object);
965 return hr;
968 TRACE("(%p) : Created volume %p.\n", This, object);
969 *ppVolume = (IWineD3DVolume *)object;
971 return WINED3D_OK;
974 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
975 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
976 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
979 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
980 HRESULT hr;
982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
983 if (!object)
985 ERR("Out of memory\n");
986 *ppCubeTexture = NULL;
987 return WINED3DERR_OUTOFVIDEOMEMORY;
990 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
991 if (FAILED(hr))
993 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
994 HeapFree(GetProcessHeap(), 0, object);
995 *ppCubeTexture = NULL;
996 return hr;
999 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1000 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1002 return WINED3D_OK;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1006 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DQueryImpl *object;
1010 HRESULT hr;
1012 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1015 if (!object)
1017 ERR("Failed to allocate query memory.\n");
1018 return E_OUTOFMEMORY;
1021 hr = query_init(object, This, type, parent);
1022 if (FAILED(hr))
1024 WARN("Failed to initialize query, hr %#x.\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1026 return hr;
1029 TRACE("Created query %p.\n", object);
1030 *query = (IWineD3DQuery *)object;
1032 return WINED3D_OK;
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1036 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1037 IUnknown *parent, WINED3DSURFTYPE surface_type)
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DSwapChainImpl *object;
1041 HRESULT hr;
1043 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1044 iface, present_parameters, swapchain, parent, surface_type);
1046 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1047 if (!object)
1049 ERR("Failed to allocate swapchain memory.\n");
1050 return E_OUTOFMEMORY;
1053 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1054 if (FAILED(hr))
1056 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1057 HeapFree(GetProcessHeap(), 0, object);
1058 return hr;
1061 TRACE("Created swapchain %p.\n", object);
1062 *swapchain = (IWineD3DSwapChain *)object;
1064 return WINED3D_OK;
1067 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1068 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1070 TRACE("(%p)\n", This);
1072 return This->NumberOfSwapChains;
1075 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1077 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1079 if(iSwapChain < This->NumberOfSwapChains) {
1080 *pSwapChain = This->swapchains[iSwapChain];
1081 IWineD3DSwapChain_AddRef(*pSwapChain);
1082 TRACE("(%p) returning %p\n", This, *pSwapChain);
1083 return WINED3D_OK;
1084 } else {
1085 TRACE("Swapchain out of range\n");
1086 *pSwapChain = NULL;
1087 return WINED3DERR_INVALIDCALL;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1092 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1093 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1096 IWineD3DVertexDeclarationImpl *object = NULL;
1097 HRESULT hr;
1099 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1100 iface, declaration, parent, elements, element_count);
1102 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1103 if(!object)
1105 ERR("Failed to allocate vertex declaration memory.\n");
1106 return E_OUTOFMEMORY;
1109 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1110 if (FAILED(hr))
1112 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1113 HeapFree(GetProcessHeap(), 0, object);
1114 return hr;
1117 TRACE("Created vertex declaration %p.\n", object);
1118 *declaration = (IWineD3DVertexDeclaration *)object;
1120 return WINED3D_OK;
1123 struct wined3d_fvf_convert_state
1125 const struct wined3d_gl_info *gl_info;
1126 WINED3DVERTEXELEMENT *elements;
1127 UINT offset;
1128 UINT idx;
1131 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1132 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1134 WINED3DVERTEXELEMENT *elements = state->elements;
1135 const struct wined3d_format_desc *format_desc;
1136 UINT offset = state->offset;
1137 UINT idx = state->idx;
1139 elements[idx].format = format;
1140 elements[idx].input_slot = 0;
1141 elements[idx].offset = offset;
1142 elements[idx].output_slot = 0;
1143 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1144 elements[idx].usage = usage;
1145 elements[idx].usage_idx = usage_idx;
1147 format_desc = getFormatDescEntry(format, state->gl_info);
1148 state->offset += format_desc->component_count * format_desc->component_size;
1149 ++state->idx;
1152 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1153 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1155 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1156 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1157 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1158 BOOL has_blend_idx = has_blend &&
1159 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1160 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1161 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1162 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1163 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1164 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1165 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1167 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1168 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1169 struct wined3d_fvf_convert_state state;
1170 unsigned int size;
1171 unsigned int idx;
1172 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1173 if (has_blend_idx) num_blends--;
1175 /* Compute declaration size */
1176 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1177 has_psize + has_diffuse + has_specular + num_textures;
1179 state.gl_info = gl_info;
1180 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1181 if (!state.elements) return ~0U;
1182 state.offset = 0;
1183 state.idx = 0;
1185 if (has_pos)
1187 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1188 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1189 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1190 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1191 else
1192 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1195 if (has_blend && (num_blends > 0))
1197 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1198 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1199 else
1201 switch (num_blends)
1203 case 1:
1204 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1205 break;
1206 case 2:
1207 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1208 break;
1209 case 3:
1210 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1211 break;
1212 case 4:
1213 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1214 break;
1215 default:
1216 ERR("Unexpected amount of blend values: %u\n", num_blends);
1221 if (has_blend_idx)
1223 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1224 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1225 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1226 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1227 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1228 else
1229 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1232 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1233 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1234 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1235 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1237 for (idx = 0; idx < num_textures; ++idx)
1239 switch ((texcoords >> (idx * 2)) & 0x03)
1241 case WINED3DFVF_TEXTUREFORMAT1:
1242 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1243 break;
1244 case WINED3DFVF_TEXTUREFORMAT2:
1245 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1246 break;
1247 case WINED3DFVF_TEXTUREFORMAT3:
1248 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1249 break;
1250 case WINED3DFVF_TEXTUREFORMAT4:
1251 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1252 break;
1256 *ppVertexElements = state.elements;
1257 return size;
1260 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1261 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1262 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1265 WINED3DVERTEXELEMENT *elements;
1266 unsigned int size;
1267 DWORD hr;
1269 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1271 size = ConvertFvfToDeclaration(This, fvf, &elements);
1272 if (size == ~0U) return E_OUTOFMEMORY;
1274 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1275 HeapFree(GetProcessHeap(), 0, elements);
1276 return hr;
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1280 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1281 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1282 const struct wined3d_parent_ops *parent_ops)
1284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1285 IWineD3DVertexShaderImpl *object;
1286 HRESULT hr;
1288 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1289 if (!object)
1291 ERR("Failed to allocate shader memory.\n");
1292 return E_OUTOFMEMORY;
1295 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1296 if (FAILED(hr))
1298 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1299 HeapFree(GetProcessHeap(), 0, object);
1300 return hr;
1303 TRACE("Created vertex shader %p.\n", object);
1304 *ppVertexShader = (IWineD3DVertexShader *)object;
1306 return WINED3D_OK;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1310 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1311 IWineD3DGeometryShader **shader, IUnknown *parent,
1312 const struct wined3d_parent_ops *parent_ops)
1314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1315 struct wined3d_geometryshader *object;
1316 HRESULT hr;
1318 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1319 if (!object)
1321 ERR("Failed to allocate shader memory.\n");
1322 return E_OUTOFMEMORY;
1325 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1326 if (FAILED(hr))
1328 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1329 HeapFree(GetProcessHeap(), 0, object);
1330 return hr;
1333 TRACE("Created geometry shader %p.\n", object);
1334 *shader = (IWineD3DGeometryShader *)object;
1336 return WINED3D_OK;
1339 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1340 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1341 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1342 const struct wined3d_parent_ops *parent_ops)
1344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1345 IWineD3DPixelShaderImpl *object;
1346 HRESULT hr;
1348 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1349 if (!object)
1351 ERR("Failed to allocate shader memory.\n");
1352 return E_OUTOFMEMORY;
1355 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1356 if (FAILED(hr))
1358 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1359 HeapFree(GetProcessHeap(), 0, object);
1360 return hr;
1363 TRACE("Created pixel shader %p.\n", object);
1364 *ppPixelShader = (IWineD3DPixelShader *)object;
1366 return WINED3D_OK;
1369 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1370 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1373 IWineD3DPaletteImpl *object;
1374 HRESULT hr;
1376 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1377 iface, Flags, PalEnt, Palette, Parent);
1379 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1380 if (!object)
1382 ERR("Failed to allocate palette memory.\n");
1383 return E_OUTOFMEMORY;
1386 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1387 if (FAILED(hr))
1389 WARN("Failed to initialize palette, hr %#x.\n", hr);
1390 HeapFree(GetProcessHeap(), 0, object);
1391 return hr;
1394 TRACE("Created palette %p.\n", object);
1395 *Palette = (IWineD3DPalette *)object;
1397 return WINED3D_OK;
1400 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1401 HBITMAP hbm;
1402 BITMAP bm;
1403 HRESULT hr;
1404 HDC dcb = NULL, dcs = NULL;
1405 WINEDDCOLORKEY colorkey;
1407 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1408 if(hbm)
1410 GetObjectA(hbm, sizeof(BITMAP), &bm);
1411 dcb = CreateCompatibleDC(NULL);
1412 if(!dcb) goto out;
1413 SelectObject(dcb, hbm);
1415 else
1417 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1418 * couldn't be loaded
1420 memset(&bm, 0, sizeof(bm));
1421 bm.bmWidth = 32;
1422 bm.bmHeight = 32;
1425 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1426 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1427 NULL, &wined3d_null_parent_ops);
1428 if(FAILED(hr)) {
1429 ERR("Wine logo requested, but failed to create surface\n");
1430 goto out;
1433 if(dcb) {
1434 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1435 if(FAILED(hr)) goto out;
1436 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1437 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1439 colorkey.dwColorSpaceLowValue = 0;
1440 colorkey.dwColorSpaceHighValue = 0;
1441 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1442 } else {
1443 /* Fill the surface with a white color to show that wined3d is there */
1444 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1447 out:
1448 if (dcb) DeleteDC(dcb);
1449 if (hbm) DeleteObject(hbm);
1452 /* Context activation is done by the caller. */
1453 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1455 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1456 unsigned int i;
1457 /* Under DirectX you can have texture stage operations even if no texture is
1458 bound, whereas opengl will only do texture operations when a valid texture is
1459 bound. We emulate this by creating dummy textures and binding them to each
1460 texture stage, but disable all stages by default. Hence if a stage is enabled
1461 then the default texture will kick in until replaced by a SetTexture call */
1462 ENTER_GL();
1464 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1466 /* The dummy texture does not have client storage backing */
1467 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1468 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1471 for (i = 0; i < gl_info->limits.textures; ++i)
1473 GLubyte white = 255;
1475 /* Make appropriate texture active */
1476 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1477 checkGLcall("glActiveTextureARB");
1479 /* Generate an opengl texture name */
1480 glGenTextures(1, &This->dummyTextureName[i]);
1481 checkGLcall("glGenTextures");
1482 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1484 /* Generate a dummy 2d texture (not using 1d because they cause many
1485 * DRI drivers fall back to sw) */
1486 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1487 checkGLcall("glBindTexture");
1489 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1490 checkGLcall("glTexImage2D");
1493 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1495 /* Reenable because if supported it is enabled by default */
1496 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1497 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1500 LEAVE_GL();
1503 /* Context activation is done by the caller. */
1504 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1506 ENTER_GL();
1507 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1508 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1509 LEAVE_GL();
1511 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1514 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1516 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1518 if (!wined3d_register_window(window, device))
1520 ERR("Failed to register window %p.\n", window);
1521 return E_FAIL;
1524 device->focus_window = window;
1525 SetForegroundWindow(window);
1527 return WINED3D_OK;
1530 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1532 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1534 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1535 device->focus_window = NULL;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1539 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1542 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1543 IWineD3DSwapChainImpl *swapchain = NULL;
1544 struct wined3d_context *context;
1545 HRESULT hr;
1546 DWORD state;
1547 unsigned int i;
1549 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1551 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1552 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1554 TRACE("(%p) : Creating stateblock\n", This);
1555 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1556 hr = IWineD3DDevice_CreateStateBlock(iface,
1557 WINED3DSBT_INIT,
1558 (IWineD3DStateBlock **)&This->stateBlock,
1559 NULL);
1560 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1561 WARN("Failed to create stateblock\n");
1562 goto err_out;
1564 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1565 This->updateStateBlock = This->stateBlock;
1566 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1568 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1569 sizeof(*This->render_targets) * gl_info->limits.buffers);
1570 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1571 sizeof(GLenum) * gl_info->limits.buffers);
1573 This->NumberOfPalettes = 1;
1574 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1575 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1576 ERR("Out of memory!\n");
1577 hr = E_OUTOFMEMORY;
1578 goto err_out;
1580 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1581 if(!This->palettes[0]) {
1582 ERR("Out of memory!\n");
1583 hr = E_OUTOFMEMORY;
1584 goto err_out;
1586 for (i = 0; i < 256; ++i) {
1587 This->palettes[0][i].peRed = 0xFF;
1588 This->palettes[0][i].peGreen = 0xFF;
1589 This->palettes[0][i].peBlue = 0xFF;
1590 This->palettes[0][i].peFlags = 0xFF;
1592 This->currentPalette = 0;
1594 /* Initialize the texture unit mapping to a 1:1 mapping */
1595 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1597 if (state < gl_info->limits.fragment_samplers)
1599 This->texUnitMap[state] = state;
1600 This->rev_tex_unit_map[state] = state;
1601 } else {
1602 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1603 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1607 /* Setup the implicit swapchain. This also initializes a context. */
1608 TRACE("Creating implicit swapchain\n");
1609 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1610 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1611 if (FAILED(hr))
1613 WARN("Failed to create implicit swapchain\n");
1614 goto err_out;
1617 This->NumberOfSwapChains = 1;
1618 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1619 if(!This->swapchains) {
1620 ERR("Out of memory!\n");
1621 goto err_out;
1623 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1625 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1626 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1627 This->render_targets[0] = (IWineD3DSurfaceImpl *)swapchain->backBuffer[0];
1629 else {
1630 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1631 This->render_targets[0] = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
1633 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1635 /* Depth Stencil support */
1636 This->depth_stencil = This->auto_depth_stencil;
1637 if (This->depth_stencil)
1638 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1640 hr = This->shader_backend->shader_alloc_private(iface);
1641 if(FAILED(hr)) {
1642 TRACE("Shader private data couldn't be allocated\n");
1643 goto err_out;
1645 hr = This->frag_pipe->alloc_private(iface);
1646 if(FAILED(hr)) {
1647 TRACE("Fragment pipeline private data couldn't be allocated\n");
1648 goto err_out;
1650 hr = This->blitter->alloc_private(iface);
1651 if(FAILED(hr)) {
1652 TRACE("Blitter private data couldn't be allocated\n");
1653 goto err_out;
1656 /* Set up some starting GL setup */
1658 /* Setup all the devices defaults */
1659 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1661 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1663 create_dummy_textures(This);
1665 ENTER_GL();
1667 /* Initialize the current view state */
1668 This->view_ident = 1;
1669 This->contexts[0]->last_was_rhw = 0;
1670 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1671 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1673 switch(wined3d_settings.offscreen_rendering_mode) {
1674 case ORM_FBO:
1675 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1676 break;
1678 case ORM_BACKBUFFER:
1680 if (context_get_current()->aux_buffers > 0)
1682 TRACE("Using auxilliary buffer for offscreen rendering\n");
1683 This->offscreenBuffer = GL_AUX0;
1684 } else {
1685 TRACE("Using back buffer for offscreen rendering\n");
1686 This->offscreenBuffer = GL_BACK;
1691 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1692 LEAVE_GL();
1694 context_release(context);
1696 /* Clear the screen */
1697 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1698 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1699 0x00, 1.0f, 0);
1701 This->d3d_initialized = TRUE;
1703 if(wined3d_settings.logo) {
1704 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1706 This->highest_dirty_ps_const = 0;
1707 This->highest_dirty_vs_const = 0;
1708 return WINED3D_OK;
1710 err_out:
1711 HeapFree(GetProcessHeap(), 0, This->render_targets);
1712 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1713 HeapFree(GetProcessHeap(), 0, This->swapchains);
1714 This->NumberOfSwapChains = 0;
1715 if(This->palettes) {
1716 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1717 HeapFree(GetProcessHeap(), 0, This->palettes);
1719 This->NumberOfPalettes = 0;
1720 if(swapchain) {
1721 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1723 if(This->stateBlock) {
1724 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1725 This->stateBlock = NULL;
1727 if (This->blit_priv) {
1728 This->blitter->free_private(iface);
1730 if (This->fragment_priv) {
1731 This->frag_pipe->free_private(iface);
1733 if (This->shader_priv) {
1734 This->shader_backend->shader_free_private(iface);
1736 return hr;
1739 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1740 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1743 IWineD3DSwapChainImpl *swapchain = NULL;
1744 HRESULT hr;
1746 /* Setup the implicit swapchain */
1747 TRACE("Creating implicit swapchain\n");
1748 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1749 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1750 if (FAILED(hr))
1752 WARN("Failed to create implicit swapchain\n");
1753 goto err_out;
1756 This->NumberOfSwapChains = 1;
1757 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1758 if(!This->swapchains) {
1759 ERR("Out of memory!\n");
1760 goto err_out;
1762 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1763 return WINED3D_OK;
1765 err_out:
1766 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1767 return hr;
1770 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1772 IWineD3DResource_UnLoad(resource);
1773 IWineD3DResource_Release(resource);
1774 return WINED3D_OK;
1777 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1778 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1781 const struct wined3d_gl_info *gl_info;
1782 struct wined3d_context *context;
1783 int sampler;
1784 UINT i;
1785 TRACE("(%p)\n", This);
1787 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1789 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1790 * it was created. Thus make sure a context is active for the glDelete* calls
1792 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1793 gl_info = context->gl_info;
1795 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1797 /* Unload resources */
1798 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1800 TRACE("Deleting high order patches\n");
1801 for(i = 0; i < PATCHMAP_SIZE; i++) {
1802 struct list *e1, *e2;
1803 struct WineD3DRectPatch *patch;
1804 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1805 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1806 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1810 /* Delete the mouse cursor texture */
1811 if(This->cursorTexture) {
1812 ENTER_GL();
1813 glDeleteTextures(1, &This->cursorTexture);
1814 LEAVE_GL();
1815 This->cursorTexture = 0;
1818 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1819 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1821 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1822 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1825 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1826 * private data, it might contain opengl pointers
1828 if(This->depth_blt_texture) {
1829 ENTER_GL();
1830 glDeleteTextures(1, &This->depth_blt_texture);
1831 LEAVE_GL();
1832 This->depth_blt_texture = 0;
1834 if (This->depth_blt_rb) {
1835 ENTER_GL();
1836 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1837 LEAVE_GL();
1838 This->depth_blt_rb = 0;
1839 This->depth_blt_rb_w = 0;
1840 This->depth_blt_rb_h = 0;
1843 /* Release the update stateblock */
1844 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1845 if(This->updateStateBlock != This->stateBlock)
1846 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1848 This->updateStateBlock = NULL;
1850 { /* because were not doing proper internal refcounts releasing the primary state block
1851 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1852 to set this->stateBlock = NULL; first */
1853 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1854 This->stateBlock = NULL;
1856 /* Release the stateblock */
1857 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1858 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1862 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1863 This->blitter->free_private(iface);
1864 This->frag_pipe->free_private(iface);
1865 This->shader_backend->shader_free_private(iface);
1867 /* Release the buffers (with sanity checks)*/
1868 if (This->onscreen_depth_stencil)
1870 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1871 This->onscreen_depth_stencil = NULL;
1874 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1875 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1877 if (This->auto_depth_stencil != This->depth_stencil)
1878 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1880 This->depth_stencil = NULL;
1882 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1883 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1885 TRACE("Setting rendertarget to NULL\n");
1886 This->render_targets[0] = NULL;
1888 if (This->auto_depth_stencil)
1890 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1892 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1894 This->auto_depth_stencil = NULL;
1897 context_release(context);
1899 for(i=0; i < This->NumberOfSwapChains; i++) {
1900 TRACE("Releasing the implicit swapchain %d\n", i);
1901 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1902 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1906 HeapFree(GetProcessHeap(), 0, This->swapchains);
1907 This->swapchains = NULL;
1908 This->NumberOfSwapChains = 0;
1910 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1911 HeapFree(GetProcessHeap(), 0, This->palettes);
1912 This->palettes = NULL;
1913 This->NumberOfPalettes = 0;
1915 HeapFree(GetProcessHeap(), 0, This->render_targets);
1916 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1917 This->render_targets = NULL;
1918 This->draw_buffers = NULL;
1920 This->d3d_initialized = FALSE;
1922 return WINED3D_OK;
1925 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1927 unsigned int i;
1929 for(i=0; i < This->NumberOfSwapChains; i++) {
1930 TRACE("Releasing the implicit swapchain %d\n", i);
1931 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1932 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1936 HeapFree(GetProcessHeap(), 0, This->swapchains);
1937 This->swapchains = NULL;
1938 This->NumberOfSwapChains = 0;
1939 return WINED3D_OK;
1942 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1943 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1944 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1946 * There is no way to deactivate thread safety once it is enabled.
1948 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1951 /*For now just store the flag(needed in case of ddraw) */
1952 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1955 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1956 const WINED3DDISPLAYMODE* pMode) {
1957 DEVMODEW devmode;
1958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1959 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1960 LONG ret;
1961 RECT clip_rc;
1963 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1965 /* Resize the screen even without a window:
1966 * The app could have unset it with SetCooperativeLevel, but not called
1967 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1968 * but we don't have any hwnd
1971 memset(&devmode, 0, sizeof(devmode));
1972 devmode.dmSize = sizeof(devmode);
1973 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1974 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1975 devmode.dmPelsWidth = pMode->Width;
1976 devmode.dmPelsHeight = pMode->Height;
1978 devmode.dmDisplayFrequency = pMode->RefreshRate;
1979 if (pMode->RefreshRate != 0) {
1980 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1983 /* Only change the mode if necessary */
1984 if( (This->ddraw_width == pMode->Width) &&
1985 (This->ddraw_height == pMode->Height) &&
1986 (This->ddraw_format == pMode->Format) &&
1987 (pMode->RefreshRate == 0) ) {
1988 return WINED3D_OK;
1991 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1992 if (ret != DISP_CHANGE_SUCCESSFUL) {
1993 if(devmode.dmDisplayFrequency != 0) {
1994 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1995 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1996 devmode.dmDisplayFrequency = 0;
1997 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1999 if(ret != DISP_CHANGE_SUCCESSFUL) {
2000 return WINED3DERR_NOTAVAILABLE;
2004 /* Store the new values */
2005 This->ddraw_width = pMode->Width;
2006 This->ddraw_height = pMode->Height;
2007 This->ddraw_format = pMode->Format;
2009 /* And finally clip mouse to our screen */
2010 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2011 ClipCursor(&clip_rc);
2013 return WINED3D_OK;
2016 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2018 *ppD3D = This->wined3d;
2019 TRACE("Returning %p.\n", *ppD3D);
2020 IWineD3D_AddRef(*ppD3D);
2021 return WINED3D_OK;
2024 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2027 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2028 (This->adapter->TextureRam/(1024*1024)),
2029 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2030 /* return simulated texture memory left */
2031 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2034 /*****
2035 * Get / Set Stream Source
2036 *****/
2037 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2038 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2041 IWineD3DBuffer *oldSrc;
2043 if (StreamNumber >= MAX_STREAMS) {
2044 WARN("Stream out of range %d\n", StreamNumber);
2045 return WINED3DERR_INVALIDCALL;
2046 } else if(OffsetInBytes & 0x3) {
2047 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2048 return WINED3DERR_INVALIDCALL;
2051 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2052 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2054 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2056 if(oldSrc == pStreamData &&
2057 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2058 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2059 TRACE("Application is setting the old values over, nothing to do\n");
2060 return WINED3D_OK;
2063 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2064 if (pStreamData) {
2065 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2066 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2069 /* Handle recording of state blocks */
2070 if (This->isRecordingState) {
2071 TRACE("Recording... not performing anything\n");
2072 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2073 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2074 return WINED3D_OK;
2077 if (pStreamData != NULL) {
2078 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2079 IWineD3DBuffer_AddRef(pStreamData);
2081 if (oldSrc != NULL) {
2082 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2083 IWineD3DBuffer_Release(oldSrc);
2086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2088 return WINED3D_OK;
2091 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2092 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2096 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2097 This->stateBlock->streamSource[StreamNumber],
2098 This->stateBlock->streamOffset[StreamNumber],
2099 This->stateBlock->streamStride[StreamNumber]);
2101 if (StreamNumber >= MAX_STREAMS) {
2102 WARN("Stream out of range %d\n", StreamNumber);
2103 return WINED3DERR_INVALIDCALL;
2105 *pStream = This->stateBlock->streamSource[StreamNumber];
2106 *pStride = This->stateBlock->streamStride[StreamNumber];
2107 if (pOffset) {
2108 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2111 if (*pStream != NULL) {
2112 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2114 return WINED3D_OK;
2117 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2120 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2122 /* Verify input at least in d3d9 this is invalid*/
2123 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2124 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2125 return WINED3DERR_INVALIDCALL;
2127 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2128 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2129 return WINED3DERR_INVALIDCALL;
2131 if( Divider == 0 ){
2132 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2133 return WINED3DERR_INVALIDCALL;
2136 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2137 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2139 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2140 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2142 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2143 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2147 return WINED3D_OK;
2150 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2153 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2154 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2156 TRACE("(%p) : returning %d\n", This, *Divider);
2158 return WINED3D_OK;
2161 /*****
2162 * Get / Set & Multiply Transform
2163 *****/
2164 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2167 /* Most of this routine, comments included copied from ddraw tree initially: */
2168 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2170 /* Handle recording of state blocks */
2171 if (This->isRecordingState) {
2172 TRACE("Recording... not performing anything\n");
2173 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2174 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2175 return WINED3D_OK;
2179 * If the new matrix is the same as the current one,
2180 * we cut off any further processing. this seems to be a reasonable
2181 * optimization because as was noticed, some apps (warcraft3 for example)
2182 * tend towards setting the same matrix repeatedly for some reason.
2184 * From here on we assume that the new matrix is different, wherever it matters.
2186 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2187 TRACE("The app is setting the same matrix over again\n");
2188 return WINED3D_OK;
2189 } else {
2190 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2194 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2195 where ViewMat = Camera space, WorldMat = world space.
2197 In OpenGL, camera and world space is combined into GL_MODELVIEW
2198 matrix. The Projection matrix stay projection matrix.
2201 /* Capture the times we can just ignore the change for now */
2202 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2203 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2204 /* Handled by the state manager */
2207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2208 return WINED3D_OK;
2211 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2213 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2214 *pMatrix = This->stateBlock->transforms[State];
2215 return WINED3D_OK;
2218 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2219 const WINED3DMATRIX *mat = NULL;
2220 WINED3DMATRIX temp;
2222 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2223 * below means it will be recorded in a state block change, but it
2224 * works regardless where it is recorded.
2225 * If this is found to be wrong, change to StateBlock.
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2228 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2230 if (State <= HIGHEST_TRANSFORMSTATE)
2232 mat = &This->updateStateBlock->transforms[State];
2233 } else {
2234 FIXME("Unhandled transform state!!\n");
2237 multiply_matrix(&temp, mat, pMatrix);
2239 /* Apply change via set transform - will reapply to eg. lights this way */
2240 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2243 /*****
2244 * Get / Set Light
2245 *****/
2246 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2247 you can reference any indexes you want as long as that number max are enabled at any
2248 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2249 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2250 but when recording, just build a chain pretty much of commands to be replayed. */
2252 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2253 float rho;
2254 struct wined3d_light_info *object = NULL;
2255 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2256 struct list *e;
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2259 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2261 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2262 * the gl driver.
2264 if(!pLight) {
2265 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2266 return WINED3DERR_INVALIDCALL;
2269 switch(pLight->Type) {
2270 case WINED3DLIGHT_POINT:
2271 case WINED3DLIGHT_SPOT:
2272 case WINED3DLIGHT_PARALLELPOINT:
2273 case WINED3DLIGHT_GLSPOT:
2274 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2275 * most wanted
2277 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2279 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2280 return WINED3DERR_INVALIDCALL;
2282 break;
2284 case WINED3DLIGHT_DIRECTIONAL:
2285 /* Ignores attenuation */
2286 break;
2288 default:
2289 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2290 return WINED3DERR_INVALIDCALL;
2293 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2295 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2296 if(object->OriginalIndex == Index) break;
2297 object = NULL;
2300 if(!object) {
2301 TRACE("Adding new light\n");
2302 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2303 if(!object) {
2304 ERR("Out of memory error when allocating a light\n");
2305 return E_OUTOFMEMORY;
2307 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2308 object->glIndex = -1;
2309 object->OriginalIndex = Index;
2312 /* Initialize the object */
2313 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,
2314 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2315 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2316 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2317 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2318 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2319 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2321 /* Save away the information */
2322 object->OriginalParms = *pLight;
2324 switch (pLight->Type) {
2325 case WINED3DLIGHT_POINT:
2326 /* Position */
2327 object->lightPosn[0] = pLight->Position.x;
2328 object->lightPosn[1] = pLight->Position.y;
2329 object->lightPosn[2] = pLight->Position.z;
2330 object->lightPosn[3] = 1.0f;
2331 object->cutoff = 180.0f;
2332 /* FIXME: Range */
2333 break;
2335 case WINED3DLIGHT_DIRECTIONAL:
2336 /* Direction */
2337 object->lightPosn[0] = -pLight->Direction.x;
2338 object->lightPosn[1] = -pLight->Direction.y;
2339 object->lightPosn[2] = -pLight->Direction.z;
2340 object->lightPosn[3] = 0.0f;
2341 object->exponent = 0.0f;
2342 object->cutoff = 180.0f;
2343 break;
2345 case WINED3DLIGHT_SPOT:
2346 /* Position */
2347 object->lightPosn[0] = pLight->Position.x;
2348 object->lightPosn[1] = pLight->Position.y;
2349 object->lightPosn[2] = pLight->Position.z;
2350 object->lightPosn[3] = 1.0f;
2352 /* Direction */
2353 object->lightDirn[0] = pLight->Direction.x;
2354 object->lightDirn[1] = pLight->Direction.y;
2355 object->lightDirn[2] = pLight->Direction.z;
2356 object->lightDirn[3] = 1.0f;
2359 * opengl-ish and d3d-ish spot lights use too different models for the
2360 * light "intensity" as a function of the angle towards the main light direction,
2361 * so we only can approximate very roughly.
2362 * however spot lights are rather rarely used in games (if ever used at all).
2363 * furthermore if still used, probably nobody pays attention to such details.
2365 if (pLight->Falloff == 0) {
2366 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2367 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2368 * will always be 1.0 for both of them, and we don't have to care for the
2369 * rest of the rather complex calculation
2371 object->exponent = 0.0f;
2372 } else {
2373 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2374 if (rho < 0.0001f) rho = 0.0001f;
2375 object->exponent = -0.3f/logf(cosf(rho/2));
2377 if (object->exponent > 128.0f)
2379 object->exponent = 128.0f;
2381 object->cutoff = pLight->Phi*90/M_PI;
2383 /* FIXME: Range */
2384 break;
2386 default:
2387 FIXME("Unrecognized light type %d\n", pLight->Type);
2390 /* Update the live definitions if the light is currently assigned a glIndex */
2391 if (object->glIndex != -1 && !This->isRecordingState) {
2392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2394 return WINED3D_OK;
2397 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2399 struct wined3d_light_info *lightInfo = NULL;
2400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2402 struct list *e;
2403 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2405 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2407 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2408 if(lightInfo->OriginalIndex == Index) break;
2409 lightInfo = NULL;
2412 if (lightInfo == NULL) {
2413 TRACE("Light information requested but light not defined\n");
2414 return WINED3DERR_INVALIDCALL;
2417 *pLight = lightInfo->OriginalParms;
2418 return WINED3D_OK;
2421 /*****
2422 * Get / Set Light Enable
2423 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2424 *****/
2425 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2427 struct wined3d_light_info *lightInfo = NULL;
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2429 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2430 struct list *e;
2431 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2433 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2435 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2436 if(lightInfo->OriginalIndex == Index) break;
2437 lightInfo = NULL;
2439 TRACE("Found light: %p\n", lightInfo);
2441 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2442 if (lightInfo == NULL) {
2444 TRACE("Light enabled requested but light not defined, so defining one!\n");
2445 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2447 /* Search for it again! Should be fairly quick as near head of list */
2448 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2450 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2451 if(lightInfo->OriginalIndex == Index) break;
2452 lightInfo = NULL;
2454 if (lightInfo == NULL) {
2455 FIXME("Adding default lights has failed dismally\n");
2456 return WINED3DERR_INVALIDCALL;
2460 if(!Enable) {
2461 if(lightInfo->glIndex != -1) {
2462 if(!This->isRecordingState) {
2463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2466 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2467 lightInfo->glIndex = -1;
2468 } else {
2469 TRACE("Light already disabled, nothing to do\n");
2471 lightInfo->enabled = FALSE;
2472 } else {
2473 lightInfo->enabled = TRUE;
2474 if (lightInfo->glIndex != -1) {
2475 /* nop */
2476 TRACE("Nothing to do as light was enabled\n");
2477 } else {
2478 int i;
2479 /* Find a free gl light */
2480 for(i = 0; i < This->maxConcurrentLights; i++) {
2481 if(This->updateStateBlock->activeLights[i] == NULL) {
2482 This->updateStateBlock->activeLights[i] = lightInfo;
2483 lightInfo->glIndex = i;
2484 break;
2487 if(lightInfo->glIndex == -1) {
2488 /* Our tests show that Windows returns D3D_OK in this situation, even with
2489 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2490 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2491 * as well for those lights.
2493 * TODO: Test how this affects rendering
2495 WARN("Too many concurrently active lights\n");
2496 return WINED3D_OK;
2499 /* i == lightInfo->glIndex */
2500 if(!This->isRecordingState) {
2501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2506 return WINED3D_OK;
2509 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2511 struct wined3d_light_info *lightInfo = NULL;
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 struct list *e;
2514 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2515 TRACE("(%p) : for idx(%d)\n", This, Index);
2517 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2519 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2520 if(lightInfo->OriginalIndex == Index) break;
2521 lightInfo = NULL;
2524 if (lightInfo == NULL) {
2525 TRACE("Light enabled state requested but light not defined\n");
2526 return WINED3DERR_INVALIDCALL;
2528 /* true is 128 according to SetLightEnable */
2529 *pEnable = lightInfo->enabled ? 128 : 0;
2530 return WINED3D_OK;
2533 /*****
2534 * Get / Set Clip Planes
2535 *****/
2536 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2538 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2540 /* Validate Index */
2541 if (Index >= This->adapter->gl_info.limits.clipplanes)
2543 TRACE("Application has requested clipplane this device doesn't support\n");
2544 return WINED3DERR_INVALIDCALL;
2547 This->updateStateBlock->changed.clipplane |= 1 << Index;
2549 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2550 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2551 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2552 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2553 TRACE("Application is setting old values over, nothing to do\n");
2554 return WINED3D_OK;
2557 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2558 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2559 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2560 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2562 /* Handle recording of state blocks */
2563 if (This->isRecordingState) {
2564 TRACE("Recording... not performing anything\n");
2565 return WINED3D_OK;
2568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2570 return WINED3D_OK;
2573 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2575 TRACE("(%p) : for idx %d\n", This, Index);
2577 /* Validate Index */
2578 if (Index >= This->adapter->gl_info.limits.clipplanes)
2580 TRACE("Application has requested clipplane this device doesn't support\n");
2581 return WINED3DERR_INVALIDCALL;
2584 pPlane[0] = This->stateBlock->clipplane[Index][0];
2585 pPlane[1] = This->stateBlock->clipplane[Index][1];
2586 pPlane[2] = This->stateBlock->clipplane[Index][2];
2587 pPlane[3] = This->stateBlock->clipplane[Index][3];
2588 return WINED3D_OK;
2591 /*****
2592 * Get / Set Clip Plane Status
2593 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2594 *****/
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2597 FIXME("(%p) : stub\n", This);
2598 if (NULL == pClipStatus) {
2599 return WINED3DERR_INVALIDCALL;
2601 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2602 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2603 return WINED3D_OK;
2606 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 FIXME("(%p) : stub\n", This);
2609 if (NULL == pClipStatus) {
2610 return WINED3DERR_INVALIDCALL;
2612 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2613 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2614 return WINED3D_OK;
2617 /*****
2618 * Get / Set Material
2619 *****/
2620 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 This->updateStateBlock->changed.material = TRUE;
2624 This->updateStateBlock->material = *pMaterial;
2626 /* Handle recording of state blocks */
2627 if (This->isRecordingState) {
2628 TRACE("Recording... not performing anything\n");
2629 return WINED3D_OK;
2632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2633 return WINED3D_OK;
2636 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2638 *pMaterial = This->updateStateBlock->material;
2639 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2640 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2641 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2642 pMaterial->Ambient.b, pMaterial->Ambient.a);
2643 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2644 pMaterial->Specular.b, pMaterial->Specular.a);
2645 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2646 pMaterial->Emissive.b, pMaterial->Emissive.a);
2647 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2649 return WINED3D_OK;
2652 /*****
2653 * Get / Set Indices
2654 *****/
2655 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2656 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 IWineD3DBuffer *oldIdxs;
2661 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2662 oldIdxs = This->updateStateBlock->pIndexData;
2664 This->updateStateBlock->changed.indices = TRUE;
2665 This->updateStateBlock->pIndexData = pIndexData;
2666 This->updateStateBlock->IndexFmt = fmt;
2668 /* Handle recording of state blocks */
2669 if (This->isRecordingState) {
2670 TRACE("Recording... not performing anything\n");
2671 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2672 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2673 return WINED3D_OK;
2676 if(oldIdxs != pIndexData) {
2677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2678 if(pIndexData) {
2679 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2680 IWineD3DBuffer_AddRef(pIndexData);
2682 if(oldIdxs) {
2683 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2684 IWineD3DBuffer_Release(oldIdxs);
2688 return WINED3D_OK;
2691 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 *ppIndexData = This->stateBlock->pIndexData;
2697 /* up ref count on ppindexdata */
2698 if (*ppIndexData) {
2699 IWineD3DBuffer_AddRef(*ppIndexData);
2700 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2701 }else{
2702 TRACE("(%p) No index data set\n", This);
2704 TRACE("Returning %p\n", *ppIndexData);
2706 return WINED3D_OK;
2709 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2710 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 TRACE("(%p)->(%d)\n", This, BaseIndex);
2714 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2715 TRACE("Application is setting the old value over, nothing to do\n");
2716 return WINED3D_OK;
2719 This->updateStateBlock->baseVertexIndex = BaseIndex;
2721 if (This->isRecordingState) {
2722 TRACE("Recording... not performing anything\n");
2723 return WINED3D_OK;
2725 /* The base vertex index affects the stream sources */
2726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2727 return WINED3D_OK;
2730 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2732 TRACE("(%p) : base_index %p\n", This, base_index);
2734 *base_index = This->stateBlock->baseVertexIndex;
2736 TRACE("Returning %u\n", *base_index);
2738 return WINED3D_OK;
2741 /*****
2742 * Get / Set Viewports
2743 *****/
2744 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2747 TRACE("(%p)\n", This);
2748 This->updateStateBlock->changed.viewport = TRUE;
2749 This->updateStateBlock->viewport = *pViewport;
2751 /* Handle recording of state blocks */
2752 if (This->isRecordingState) {
2753 TRACE("Recording... not performing anything\n");
2754 return WINED3D_OK;
2757 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2758 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2761 return WINED3D_OK;
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p)\n", This);
2768 *pViewport = This->stateBlock->viewport;
2769 return WINED3D_OK;
2772 /*****
2773 * Get / Set Render States
2774 * TODO: Verify against dx9 definitions
2775 *****/
2776 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 DWORD oldValue = This->stateBlock->renderState[State];
2781 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2783 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2784 This->updateStateBlock->renderState[State] = Value;
2786 /* Handle recording of state blocks */
2787 if (This->isRecordingState) {
2788 TRACE("Recording... not performing anything\n");
2789 return WINED3D_OK;
2792 /* Compared here and not before the assignment to allow proper stateblock recording */
2793 if(Value == oldValue) {
2794 TRACE("Application is setting the old value over, nothing to do\n");
2795 } else {
2796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2799 return WINED3D_OK;
2802 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2805 *pValue = This->stateBlock->renderState[State];
2806 return WINED3D_OK;
2809 /*****
2810 * Get / Set Sampler States
2811 * TODO: Verify against dx9 definitions
2812 *****/
2814 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 DWORD oldValue;
2818 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2819 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2821 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2822 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2825 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2826 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2827 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2830 * SetSampler is designed to allow for more than the standard up to 8 textures
2831 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2832 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2834 * http://developer.nvidia.com/object/General_FAQ.html#t6
2836 * There are two new settings for GForce
2837 * the sampler one:
2838 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2839 * and the texture one:
2840 * GL_MAX_TEXTURE_COORDS_ARB.
2841 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2842 ******************/
2844 oldValue = This->stateBlock->samplerState[Sampler][Type];
2845 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2846 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2848 /* Handle recording of state blocks */
2849 if (This->isRecordingState) {
2850 TRACE("Recording... not performing anything\n");
2851 return WINED3D_OK;
2854 if(oldValue == Value) {
2855 TRACE("Application is setting the old value over, nothing to do\n");
2856 return WINED3D_OK;
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2861 return WINED3D_OK;
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2867 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2868 This, Sampler, debug_d3dsamplerstate(Type), Type);
2870 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2871 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2874 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2875 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2876 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2878 *Value = This->stateBlock->samplerState[Sampler][Type];
2879 TRACE("(%p) : Returning %#x\n", This, *Value);
2881 return WINED3D_OK;
2884 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 This->updateStateBlock->changed.scissorRect = TRUE;
2888 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2889 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2890 return WINED3D_OK;
2892 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2894 if(This->isRecordingState) {
2895 TRACE("Recording... not performing anything\n");
2896 return WINED3D_OK;
2899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2901 return WINED3D_OK;
2904 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 *pRect = This->updateStateBlock->scissorRect;
2908 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2909 return WINED3D_OK;
2912 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2914 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2916 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2918 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2919 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2921 This->updateStateBlock->vertexDecl = pDecl;
2922 This->updateStateBlock->changed.vertexDecl = TRUE;
2924 if (This->isRecordingState) {
2925 TRACE("Recording... not performing anything\n");
2926 return WINED3D_OK;
2927 } else if(pDecl == oldDecl) {
2928 /* Checked after the assignment to allow proper stateblock recording */
2929 TRACE("Application is setting the old declaration over, nothing to do\n");
2930 return WINED3D_OK;
2933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2934 return WINED3D_OK;
2937 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2942 *ppDecl = This->stateBlock->vertexDecl;
2943 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2944 return WINED3D_OK;
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2951 This->updateStateBlock->vertexShader = pShader;
2952 This->updateStateBlock->changed.vertexShader = TRUE;
2954 if (This->isRecordingState) {
2955 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2956 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2957 TRACE("Recording... not performing anything\n");
2958 return WINED3D_OK;
2959 } else if(oldShader == pShader) {
2960 /* Checked here to allow proper stateblock recording */
2961 TRACE("App is setting the old shader over, nothing to do\n");
2962 return WINED3D_OK;
2965 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2966 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2967 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2971 return WINED3D_OK;
2974 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 if (NULL == ppShader) {
2978 return WINED3DERR_INVALIDCALL;
2980 *ppShader = This->stateBlock->vertexShader;
2981 if( NULL != *ppShader)
2982 IWineD3DVertexShader_AddRef(*ppShader);
2984 TRACE("(%p) : returning %p\n", This, *ppShader);
2985 return WINED3D_OK;
2988 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2989 IWineD3DDevice *iface,
2990 UINT start,
2991 CONST BOOL *srcData,
2992 UINT count) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2997 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2998 iface, srcData, start, count);
3000 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3002 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3003 for (i = 0; i < cnt; i++)
3004 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3006 for (i = start; i < cnt + start; ++i) {
3007 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3010 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3012 return WINED3D_OK;
3015 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3016 IWineD3DDevice *iface,
3017 UINT start,
3018 BOOL *dstData,
3019 UINT count) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 int cnt = min(count, MAX_CONST_B - start);
3024 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3025 iface, dstData, start, count);
3027 if (dstData == NULL || cnt < 0)
3028 return WINED3DERR_INVALIDCALL;
3030 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3031 return WINED3D_OK;
3034 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3035 IWineD3DDevice *iface,
3036 UINT start,
3037 CONST int *srcData,
3038 UINT count) {
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3043 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3044 iface, srcData, start, count);
3046 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3048 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3049 for (i = 0; i < cnt; i++)
3050 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3051 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3053 for (i = start; i < cnt + start; ++i) {
3054 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3057 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3059 return WINED3D_OK;
3062 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3063 IWineD3DDevice *iface,
3064 UINT start,
3065 int *dstData,
3066 UINT count) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 int cnt = min(count, MAX_CONST_I - start);
3071 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3072 iface, dstData, start, count);
3074 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3075 return WINED3DERR_INVALIDCALL;
3077 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3078 return WINED3D_OK;
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3082 IWineD3DDevice *iface,
3083 UINT start,
3084 CONST float *srcData,
3085 UINT count) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 UINT i;
3090 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3091 iface, srcData, start, count);
3093 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3094 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3095 return WINED3DERR_INVALIDCALL;
3097 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3098 if(TRACE_ON(d3d)) {
3099 for (i = 0; i < count; i++)
3100 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3101 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3104 if (!This->isRecordingState)
3106 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3107 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3110 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3111 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3113 return WINED3D_OK;
3116 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3117 IWineD3DDevice *iface,
3118 UINT start,
3119 float *dstData,
3120 UINT count) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 int cnt = min(count, This->d3d_vshader_constantF - start);
3125 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3126 iface, dstData, start, count);
3128 if (dstData == NULL || cnt < 0)
3129 return WINED3DERR_INVALIDCALL;
3131 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3132 return WINED3D_OK;
3135 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3136 DWORD i;
3137 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3143 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3145 DWORD i = This->rev_tex_unit_map[unit];
3146 DWORD j = This->texUnitMap[stage];
3148 This->texUnitMap[stage] = unit;
3149 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3151 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3154 This->rev_tex_unit_map[unit] = stage;
3155 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3157 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3161 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3162 int i;
3164 This->fixed_function_usage_map = 0;
3165 for (i = 0; i < MAX_TEXTURES; ++i) {
3166 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3167 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3168 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3169 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3170 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3171 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3172 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3173 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3175 if (color_op == WINED3DTOP_DISABLE) {
3176 /* Not used, and disable higher stages */
3177 break;
3180 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3181 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3182 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3183 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3184 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3185 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3186 This->fixed_function_usage_map |= (1 << i);
3189 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3190 This->fixed_function_usage_map |= (1 << (i + 1));
3195 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3197 unsigned int i, tex;
3198 WORD ffu_map;
3200 device_update_fixed_function_usage_map(This);
3201 ffu_map = This->fixed_function_usage_map;
3203 if (This->max_ffp_textures == gl_info->limits.texture_stages
3204 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3206 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3208 if (!(ffu_map & 1)) continue;
3210 if (This->texUnitMap[i] != i) {
3211 device_map_stage(This, i, i);
3212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3213 markTextureStagesDirty(This, i);
3216 return;
3219 /* Now work out the mapping */
3220 tex = 0;
3221 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3223 if (!(ffu_map & 1)) continue;
3225 if (This->texUnitMap[i] != tex) {
3226 device_map_stage(This, i, tex);
3227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3228 markTextureStagesDirty(This, i);
3231 ++tex;
3235 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3237 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3238 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3239 unsigned int i;
3241 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3242 if (sampler_type[i] && This->texUnitMap[i] != i)
3244 device_map_stage(This, i, i);
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3246 if (i < gl_info->limits.texture_stages)
3248 markTextureStagesDirty(This, i);
3254 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3255 const DWORD *vshader_sampler_tokens, DWORD unit)
3257 DWORD current_mapping = This->rev_tex_unit_map[unit];
3259 /* Not currently used */
3260 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3262 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3263 /* Used by a fragment sampler */
3265 if (!pshader_sampler_tokens) {
3266 /* No pixel shader, check fixed function */
3267 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3270 /* Pixel shader, check the shader's sampler map */
3271 return !pshader_sampler_tokens[current_mapping];
3274 /* Used by a vertex sampler */
3275 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3278 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3280 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3281 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3282 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3283 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3284 int i;
3286 if (ps) {
3287 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3289 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3290 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3291 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3294 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3295 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3296 if (vshader_sampler_type[i])
3298 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3300 /* Already mapped somewhere */
3301 continue;
3304 while (start >= 0) {
3305 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3307 device_map_stage(This, vsampler_idx, start);
3308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3310 --start;
3311 break;
3314 --start;
3320 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3322 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3323 BOOL vs = use_vs(This->stateBlock);
3324 BOOL ps = use_ps(This->stateBlock);
3326 * Rules are:
3327 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3328 * that would be really messy and require shader recompilation
3329 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3330 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3332 if (ps) device_map_psamplers(This, gl_info);
3333 else device_map_fixed_function_samplers(This, gl_info);
3335 if (vs) device_map_vsamplers(This, ps, gl_info);
3338 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3340 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3341 This->updateStateBlock->pixelShader = pShader;
3342 This->updateStateBlock->changed.pixelShader = TRUE;
3344 /* Handle recording of state blocks */
3345 if (This->isRecordingState) {
3346 TRACE("Recording... not performing anything\n");
3349 if (This->isRecordingState) {
3350 TRACE("Recording... not performing anything\n");
3351 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3352 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3353 return WINED3D_OK;
3356 if(pShader == oldShader) {
3357 TRACE("App is setting the old pixel shader over, nothing to do\n");
3358 return WINED3D_OK;
3361 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3362 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3364 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3367 return WINED3D_OK;
3370 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3373 if (NULL == ppShader) {
3374 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3375 return WINED3DERR_INVALIDCALL;
3378 *ppShader = This->stateBlock->pixelShader;
3379 if (NULL != *ppShader) {
3380 IWineD3DPixelShader_AddRef(*ppShader);
3382 TRACE("(%p) : returning %p\n", This, *ppShader);
3383 return WINED3D_OK;
3386 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3387 IWineD3DDevice *iface,
3388 UINT start,
3389 CONST BOOL *srcData,
3390 UINT count) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3393 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3395 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3396 iface, srcData, start, count);
3398 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3400 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3401 for (i = 0; i < cnt; i++)
3402 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3404 for (i = start; i < cnt + start; ++i) {
3405 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3408 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3410 return WINED3D_OK;
3413 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3414 IWineD3DDevice *iface,
3415 UINT start,
3416 BOOL *dstData,
3417 UINT count) {
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 int cnt = min(count, MAX_CONST_B - start);
3422 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3423 iface, dstData, start, count);
3425 if (dstData == NULL || cnt < 0)
3426 return WINED3DERR_INVALIDCALL;
3428 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3429 return WINED3D_OK;
3432 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3433 IWineD3DDevice *iface,
3434 UINT start,
3435 CONST int *srcData,
3436 UINT count) {
3438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3439 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3441 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3442 iface, srcData, start, count);
3444 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3446 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3447 for (i = 0; i < cnt; i++)
3448 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3449 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3451 for (i = start; i < cnt + start; ++i) {
3452 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3455 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3457 return WINED3D_OK;
3460 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3461 IWineD3DDevice *iface,
3462 UINT start,
3463 int *dstData,
3464 UINT count) {
3466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3467 int cnt = min(count, MAX_CONST_I - start);
3469 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3470 iface, dstData, start, count);
3472 if (dstData == NULL || cnt < 0)
3473 return WINED3DERR_INVALIDCALL;
3475 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3476 return WINED3D_OK;
3479 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3480 IWineD3DDevice *iface,
3481 UINT start,
3482 CONST float *srcData,
3483 UINT count) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 UINT i;
3488 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3489 iface, srcData, start, count);
3491 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3492 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3493 return WINED3DERR_INVALIDCALL;
3495 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3496 if(TRACE_ON(d3d)) {
3497 for (i = 0; i < count; i++)
3498 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3499 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3502 if (!This->isRecordingState)
3504 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3508 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3509 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3511 return WINED3D_OK;
3514 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3515 IWineD3DDevice *iface,
3516 UINT start,
3517 float *dstData,
3518 UINT count) {
3520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3521 int cnt = min(count, This->d3d_pshader_constantF - start);
3523 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3524 iface, dstData, start, count);
3526 if (dstData == NULL || cnt < 0)
3527 return WINED3DERR_INVALIDCALL;
3529 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3530 return WINED3D_OK;
3533 /* Context activation is done by the caller. */
3534 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3535 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3536 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3537 DWORD DestFVF)
3539 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3540 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3541 unsigned int i;
3542 WINED3DVIEWPORT vp;
3543 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3544 BOOL doClip;
3545 DWORD numTextures;
3547 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3549 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3552 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3554 ERR("Source has no position mask\n");
3555 return WINED3DERR_INVALIDCALL;
3558 /* We might access VBOs from this code, so hold the lock */
3559 ENTER_GL();
3561 if (dest->resource.allocatedMemory == NULL) {
3562 buffer_get_sysmem(dest);
3565 /* Get a pointer into the destination vbo(create one if none exists) and
3566 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3568 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3570 dest->flags |= WINED3D_BUFFER_CREATEBO;
3571 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3574 if (dest->buffer_object)
3576 unsigned char extrabytes = 0;
3577 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3578 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3579 * this may write 4 extra bytes beyond the area that should be written
3581 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3582 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3583 if(!dest_conv_addr) {
3584 ERR("Out of memory\n");
3585 /* Continue without storing converted vertices */
3587 dest_conv = dest_conv_addr;
3590 /* Should I clip?
3591 * a) WINED3DRS_CLIPPING is enabled
3592 * b) WINED3DVOP_CLIP is passed
3594 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3595 static BOOL warned = FALSE;
3597 * The clipping code is not quite correct. Some things need
3598 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3599 * so disable clipping for now.
3600 * (The graphics in Half-Life are broken, and my processvertices
3601 * test crashes with IDirect3DDevice3)
3602 doClip = TRUE;
3604 doClip = FALSE;
3605 if(!warned) {
3606 warned = TRUE;
3607 FIXME("Clipping is broken and disabled for now\n");
3609 } else doClip = FALSE;
3610 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3612 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3613 WINED3DTS_VIEW,
3614 &view_mat);
3615 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3616 WINED3DTS_PROJECTION,
3617 &proj_mat);
3618 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3619 WINED3DTS_WORLDMATRIX(0),
3620 &world_mat);
3622 TRACE("View mat:\n");
3623 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);
3624 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);
3625 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);
3626 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);
3628 TRACE("Proj mat:\n");
3629 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);
3630 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);
3631 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);
3632 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);
3634 TRACE("World mat:\n");
3635 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);
3636 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);
3637 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);
3638 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);
3640 /* Get the viewport */
3641 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3642 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3643 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3645 multiply_matrix(&mat,&view_mat,&world_mat);
3646 multiply_matrix(&mat,&proj_mat,&mat);
3648 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3650 for (i = 0; i < dwCount; i+= 1) {
3651 unsigned int tex_index;
3653 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3654 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3655 /* The position first */
3656 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3657 const float *p = (const float *)(element->data + i * element->stride);
3658 float x, y, z, rhw;
3659 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3661 /* Multiplication with world, view and projection matrix */
3662 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);
3663 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);
3664 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);
3665 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);
3667 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3669 /* WARNING: The following things are taken from d3d7 and were not yet checked
3670 * against d3d8 or d3d9!
3673 /* Clipping conditions: From msdn
3675 * A vertex is clipped if it does not match the following requirements
3676 * -rhw < x <= rhw
3677 * -rhw < y <= rhw
3678 * 0 < z <= rhw
3679 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3681 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3682 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3686 if( !doClip ||
3687 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3688 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3689 ( rhw > eps ) ) ) {
3691 /* "Normal" viewport transformation (not clipped)
3692 * 1) The values are divided by rhw
3693 * 2) The y axis is negative, so multiply it with -1
3694 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3695 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3696 * 4) Multiply x with Width/2 and add Width/2
3697 * 5) The same for the height
3698 * 6) Add the viewpoint X and Y to the 2D coordinates and
3699 * The minimum Z value to z
3700 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3702 * Well, basically it's simply a linear transformation into viewport
3703 * coordinates
3706 x /= rhw;
3707 y /= rhw;
3708 z /= rhw;
3710 y *= -1;
3712 x *= vp.Width / 2;
3713 y *= vp.Height / 2;
3714 z *= vp.MaxZ - vp.MinZ;
3716 x += vp.Width / 2 + vp.X;
3717 y += vp.Height / 2 + vp.Y;
3718 z += vp.MinZ;
3720 rhw = 1 / rhw;
3721 } else {
3722 /* That vertex got clipped
3723 * Contrary to OpenGL it is not dropped completely, it just
3724 * undergoes a different calculation.
3726 TRACE("Vertex got clipped\n");
3727 x += rhw;
3728 y += rhw;
3730 x /= 2;
3731 y /= 2;
3733 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3734 * outside of the main vertex buffer memory. That needs some more
3735 * investigation...
3739 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3742 ( (float *) dest_ptr)[0] = x;
3743 ( (float *) dest_ptr)[1] = y;
3744 ( (float *) dest_ptr)[2] = z;
3745 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3747 dest_ptr += 3 * sizeof(float);
3749 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3750 dest_ptr += sizeof(float);
3753 if(dest_conv) {
3754 float w = 1 / rhw;
3755 ( (float *) dest_conv)[0] = x * w;
3756 ( (float *) dest_conv)[1] = y * w;
3757 ( (float *) dest_conv)[2] = z * w;
3758 ( (float *) dest_conv)[3] = w;
3760 dest_conv += 3 * sizeof(float);
3762 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3763 dest_conv += sizeof(float);
3767 if (DestFVF & WINED3DFVF_PSIZE) {
3768 dest_ptr += sizeof(DWORD);
3769 if(dest_conv) dest_conv += sizeof(DWORD);
3771 if (DestFVF & WINED3DFVF_NORMAL) {
3772 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3773 const float *normal = (const float *)(element->data + i * element->stride);
3774 /* AFAIK this should go into the lighting information */
3775 FIXME("Didn't expect the destination to have a normal\n");
3776 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3777 if(dest_conv) {
3778 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3782 if (DestFVF & WINED3DFVF_DIFFUSE) {
3783 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3784 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3785 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3787 static BOOL warned = FALSE;
3789 if(!warned) {
3790 ERR("No diffuse color in source, but destination has one\n");
3791 warned = TRUE;
3794 *( (DWORD *) dest_ptr) = 0xffffffff;
3795 dest_ptr += sizeof(DWORD);
3797 if(dest_conv) {
3798 *( (DWORD *) dest_conv) = 0xffffffff;
3799 dest_conv += sizeof(DWORD);
3802 else {
3803 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3804 if(dest_conv) {
3805 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3806 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3807 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3808 dest_conv += sizeof(DWORD);
3813 if (DestFVF & WINED3DFVF_SPECULAR)
3815 /* What's the color value in the feedback buffer? */
3816 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3817 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3818 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3820 static BOOL warned = FALSE;
3822 if(!warned) {
3823 ERR("No specular color in source, but destination has one\n");
3824 warned = TRUE;
3827 *( (DWORD *) dest_ptr) = 0xFF000000;
3828 dest_ptr += sizeof(DWORD);
3830 if(dest_conv) {
3831 *( (DWORD *) dest_conv) = 0xFF000000;
3832 dest_conv += sizeof(DWORD);
3835 else {
3836 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3837 if(dest_conv) {
3838 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3839 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3840 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3841 dest_conv += sizeof(DWORD);
3846 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3847 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3848 const float *tex_coord = (const float *)(element->data + i * element->stride);
3849 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3851 ERR("No source texture, but destination requests one\n");
3852 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3853 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3855 else {
3856 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3857 if(dest_conv) {
3858 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3864 if(dest_conv) {
3865 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3866 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3867 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3868 dwCount * get_flexible_vertex_size(DestFVF),
3869 dest_conv_addr));
3870 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3871 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3874 LEAVE_GL();
3876 return WINED3D_OK;
3878 #undef copy_and_next
3880 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3881 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3882 DWORD DestFVF)
3884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3885 struct wined3d_stream_info stream_info;
3886 struct wined3d_context *context;
3887 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3888 HRESULT hr;
3890 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3892 if(pVertexDecl) {
3893 ERR("Output vertex declaration not implemented yet\n");
3896 /* Need any context to write to the vbo. */
3897 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3899 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3900 * control the streamIsUP flag, thus restore it afterwards.
3902 This->stateBlock->streamIsUP = FALSE;
3903 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3904 This->stateBlock->streamIsUP = streamWasUP;
3906 if(vbo || SrcStartIndex) {
3907 unsigned int i;
3908 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3909 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3911 * Also get the start index in, but only loop over all elements if there's something to add at all.
3913 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3915 struct wined3d_stream_info_element *e;
3917 if (!(stream_info.use_map & (1 << i))) continue;
3919 e = &stream_info.elements[i];
3920 if (e->buffer_object)
3922 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3923 e->buffer_object = 0;
3924 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3925 ENTER_GL();
3926 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3927 vb->buffer_object = 0;
3928 LEAVE_GL();
3930 if (e->data) e->data += e->stride * SrcStartIndex;
3934 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3935 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3937 context_release(context);
3939 return hr;
3942 /*****
3943 * Get / Set Texture Stage States
3944 * TODO: Verify against dx9 definitions
3945 *****/
3946 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3948 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3949 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3951 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3953 if (Stage >= gl_info->limits.texture_stages)
3955 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3956 Stage, gl_info->limits.texture_stages - 1);
3957 return WINED3D_OK;
3960 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3961 This->updateStateBlock->textureState[Stage][Type] = Value;
3963 if (This->isRecordingState) {
3964 TRACE("Recording... not performing anything\n");
3965 return WINED3D_OK;
3968 /* Checked after the assignments to allow proper stateblock recording */
3969 if(oldValue == Value) {
3970 TRACE("App is setting the old value over, nothing to do\n");
3971 return WINED3D_OK;
3974 if(Stage > This->stateBlock->lowest_disabled_stage &&
3975 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3976 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3977 * Changes in other states are important on disabled stages too
3979 return WINED3D_OK;
3982 if(Type == WINED3DTSS_COLOROP) {
3983 unsigned int i;
3985 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3986 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3987 * they have to be disabled
3989 * The current stage is dirtified below.
3991 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3992 TRACE("Additionally dirtifying stage %u\n", i);
3993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3995 This->stateBlock->lowest_disabled_stage = Stage;
3996 TRACE("New lowest disabled: %u\n", Stage);
3997 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3998 /* Previously disabled stage enabled. Stages above it may need enabling
3999 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4000 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4002 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4005 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4007 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4008 break;
4010 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4013 This->stateBlock->lowest_disabled_stage = i;
4014 TRACE("New lowest disabled: %u\n", i);
4018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4020 return WINED3D_OK;
4023 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4026 *pValue = This->updateStateBlock->textureState[Stage][Type];
4027 return WINED3D_OK;
4030 /*****
4031 * Get / Set Texture
4032 *****/
4033 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4034 DWORD stage, IWineD3DBaseTexture *texture)
4036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4037 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4038 IWineD3DBaseTexture *prev;
4040 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4042 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4043 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4045 /* Windows accepts overflowing this array... we do not. */
4046 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4048 WARN("Ignoring invalid stage %u.\n", stage);
4049 return WINED3D_OK;
4052 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4053 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4055 WARN("Rejecting attempt to set scratch texture.\n");
4056 return WINED3DERR_INVALIDCALL;
4059 This->updateStateBlock->changed.textures |= 1 << stage;
4061 prev = This->updateStateBlock->textures[stage];
4062 TRACE("Previous texture %p.\n", prev);
4064 if (texture == prev)
4066 TRACE("App is setting the same texture again, nothing to do.\n");
4067 return WINED3D_OK;
4070 TRACE("Setting new texture to %p.\n", texture);
4071 This->updateStateBlock->textures[stage] = texture;
4073 if (This->isRecordingState)
4075 TRACE("Recording... not performing anything\n");
4077 if (texture) IWineD3DBaseTexture_AddRef(texture);
4078 if (prev) IWineD3DBaseTexture_Release(prev);
4080 return WINED3D_OK;
4083 if (texture)
4085 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4086 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4087 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4089 IWineD3DBaseTexture_AddRef(texture);
4091 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4096 if (!prev && stage < gl_info->limits.texture_stages)
4098 /* The source arguments for color and alpha ops have different
4099 * meanings when a NULL texture is bound, so the COLOROP and
4100 * ALPHAOP have to be dirtified. */
4101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4105 if (bind_count == 1) t->baseTexture.sampler = stage;
4108 if (prev)
4110 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4111 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4113 IWineD3DBaseTexture_Release(prev);
4115 if (!texture && stage < gl_info->limits.texture_stages)
4117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4121 if (bind_count && t->baseTexture.sampler == stage)
4123 unsigned int i;
4125 /* Search for other stages the texture is bound to. Shouldn't
4126 * happen if applications bind textures to a single stage only. */
4127 TRACE("Searching for other stages the texture is bound to.\n");
4128 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4130 if (This->updateStateBlock->textures[i] == prev)
4132 TRACE("Texture is also bound to stage %u.\n", i);
4133 t->baseTexture.sampler = i;
4134 break;
4140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4142 return WINED3D_OK;
4145 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4148 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4150 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4151 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4154 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4155 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4156 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4159 *ppTexture=This->stateBlock->textures[Stage];
4160 if (*ppTexture)
4161 IWineD3DBaseTexture_AddRef(*ppTexture);
4163 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4165 return WINED3D_OK;
4168 /*****
4169 * Get Back Buffer
4170 *****/
4171 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4172 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4174 IWineD3DSwapChain *swapchain;
4175 HRESULT hr;
4177 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4178 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4180 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4181 if (FAILED(hr))
4183 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4184 return hr;
4187 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4188 IWineD3DSwapChain_Release(swapchain);
4189 if (FAILED(hr))
4191 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4192 return hr;
4195 return WINED3D_OK;
4198 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4200 WARN("(%p) : stub, calling idirect3d for now\n", This);
4201 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4204 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4206 IWineD3DSwapChain *swapChain;
4207 HRESULT hr;
4209 if(iSwapChain > 0) {
4210 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4211 if (hr == WINED3D_OK) {
4212 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4213 IWineD3DSwapChain_Release(swapChain);
4214 } else {
4215 FIXME("(%p) Error getting display mode\n", This);
4217 } else {
4218 /* Don't read the real display mode,
4219 but return the stored mode instead. X11 can't change the color
4220 depth, and some apps are pretty angry if they SetDisplayMode from
4221 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4223 Also don't relay to the swapchain because with ddraw it's possible
4224 that there isn't a swapchain at all */
4225 pMode->Width = This->ddraw_width;
4226 pMode->Height = This->ddraw_height;
4227 pMode->Format = This->ddraw_format;
4228 pMode->RefreshRate = 0;
4229 hr = WINED3D_OK;
4232 return hr;
4235 /*****
4236 * Stateblock related functions
4237 *****/
4239 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4241 IWineD3DStateBlock *stateblock;
4242 HRESULT hr;
4244 TRACE("(%p)\n", This);
4246 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4248 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4249 if (FAILED(hr)) return hr;
4251 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4252 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4253 This->isRecordingState = TRUE;
4255 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4257 return WINED3D_OK;
4260 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4264 if (!This->isRecordingState) {
4265 WARN("(%p) not recording! returning error\n", This);
4266 *ppStateBlock = NULL;
4267 return WINED3DERR_INVALIDCALL;
4270 stateblock_init_contained_states(object);
4272 *ppStateBlock = (IWineD3DStateBlock*) object;
4273 This->isRecordingState = FALSE;
4274 This->updateStateBlock = This->stateBlock;
4275 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4276 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4277 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4278 return WINED3D_OK;
4281 /*****
4282 * Scene related functions
4283 *****/
4284 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4285 /* At the moment we have no need for any functionality at the beginning
4286 of a scene */
4287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 TRACE("(%p)\n", This);
4290 if(This->inScene) {
4291 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4292 return WINED3DERR_INVALIDCALL;
4294 This->inScene = TRUE;
4295 return WINED3D_OK;
4298 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4301 struct wined3d_context *context;
4303 TRACE("(%p)\n", This);
4305 if(!This->inScene) {
4306 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4307 return WINED3DERR_INVALIDCALL;
4310 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4311 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4312 wglFlush();
4313 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4314 * fails. */
4315 context_release(context);
4317 This->inScene = FALSE;
4318 return WINED3D_OK;
4321 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4322 const RECT *pSourceRect, const RECT *pDestRect,
4323 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4325 IWineD3DSwapChain *swapChain = NULL;
4326 int i;
4327 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4329 TRACE("iface %p.\n", iface);
4331 for(i = 0 ; i < swapchains ; i ++) {
4333 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4334 TRACE("presentinng chain %d, %p\n", i, swapChain);
4335 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4336 IWineD3DSwapChain_Release(swapChain);
4339 return WINED3D_OK;
4342 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4343 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4345 /* partial viewport*/
4346 if (viewport->X != 0 || viewport->Y != 0
4347 || viewport->Width < target->currentDesc.Width
4348 || viewport->Height < target->currentDesc.Height)
4349 return FALSE;
4351 /* partial scissor rect */
4352 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4353 || scissor_rect->right < target->currentDesc.Width
4354 || scissor_rect->bottom < target->currentDesc.Height))
4355 return FALSE;
4357 /* partial clear rect */
4358 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4359 || clear_rect->x2 < target->currentDesc.Width
4360 || clear_rect->y2 < target->currentDesc.Height))
4361 return FALSE;
4363 return TRUE;
4366 /* Not called from the VTable (internal subroutine) */
4367 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4368 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4370 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4371 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4372 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4373 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4374 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4375 GLbitfield glMask = 0;
4376 unsigned int i;
4377 WINED3DRECT curRect;
4378 RECT vp_rect;
4379 UINT drawable_width, drawable_height;
4380 struct wined3d_context *context;
4382 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4383 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4384 * for the cleared parts, and the untouched parts.
4386 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4387 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4388 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4389 * checking all this if the dest surface is in the drawable anyway.
4391 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4393 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4394 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4397 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4398 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4400 if (!surface_is_offscreen(target))
4402 TRACE("Surface %p is onscreen\n", target);
4404 ENTER_GL();
4405 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4406 context_set_draw_buffer(context, surface_get_gl_buffer(target));
4407 LEAVE_GL();
4409 else
4411 TRACE("Surface %p is offscreen\n", target);
4413 ENTER_GL();
4414 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4415 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, target);
4416 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, depth_stencil, TRUE);
4417 LEAVE_GL();
4421 if (!context->valid)
4423 context_release(context);
4424 WARN("Invalid context, skipping clear.\n");
4425 return WINED3D_OK;
4428 target->get_drawable_size(context, &drawable_width, &drawable_height);
4430 ENTER_GL();
4432 /* Only set the values up once, as they are not changing */
4433 if (Flags & WINED3DCLEAR_STENCIL)
4435 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4437 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4438 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4440 glStencilMask(~0U);
4441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4442 glClearStencil(Stencil);
4443 checkGLcall("glClearStencil");
4444 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4447 if (Flags & WINED3DCLEAR_ZBUFFER)
4449 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4451 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4452 device_switch_onscreen_ds(This, context, depth_stencil);
4454 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4455 surface_load_ds_location(depth_stencil, context, location);
4456 surface_modify_ds_location(depth_stencil, location);
4458 glDepthMask(GL_TRUE);
4459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4460 glClearDepth(Z);
4461 checkGLcall("glClearDepth");
4462 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4465 if (Flags & WINED3DCLEAR_TARGET)
4467 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4469 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4474 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4475 checkGLcall("glClearColor");
4476 glMask = glMask | GL_COLOR_BUFFER_BIT;
4479 vp_rect.left = vp->X;
4480 vp_rect.top = vp->Y;
4481 vp_rect.right = vp->X + vp->Width;
4482 vp_rect.bottom = vp->Y + vp->Height;
4483 if (!(Count > 0 && pRects)) {
4484 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4485 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4487 if (context->render_offscreen)
4489 glScissor(vp_rect.left, vp_rect.top,
4490 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4491 } else {
4492 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4493 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4495 checkGLcall("glScissor");
4496 glClear(glMask);
4497 checkGLcall("glClear");
4498 } else {
4499 /* Now process each rect in turn */
4500 for (i = 0; i < Count; i++) {
4501 /* Note gl uses lower left, width/height */
4502 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4503 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4504 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4506 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4507 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4508 curRect.x1, (target->currentDesc.Height - curRect.y2),
4509 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4511 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4512 * The rectangle is not cleared, no error is returned, but further rectanlges are
4513 * still cleared if they are valid
4515 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4516 TRACE("Rectangle with negative dimensions, ignoring\n");
4517 continue;
4520 if (context->render_offscreen)
4522 glScissor(curRect.x1, curRect.y1,
4523 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4524 } else {
4525 glScissor(curRect.x1, drawable_height - curRect.y2,
4526 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4528 checkGLcall("glScissor");
4530 glClear(glMask);
4531 checkGLcall("glClear");
4535 LEAVE_GL();
4537 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4538 && ((IWineD3DSwapChainImpl *)target->container)->frontBuffer == (IWineD3DSurface *)target))
4539 wglFlush(); /* Flush to ensure ordering across contexts. */
4541 context_release(context);
4543 return WINED3D_OK;
4546 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4547 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4552 Count, pRects, Flags, Color, Z, Stencil);
4554 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4556 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4557 /* TODO: What about depth stencil buffers without stencil bits? */
4558 return WINED3DERR_INVALIDCALL;
4561 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4564 /*****
4565 * Drawing functions
4566 *****/
4568 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4569 WINED3DPRIMITIVETYPE primitive_type)
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4575 This->updateStateBlock->changed.primitive_type = TRUE;
4576 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4579 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4580 WINED3DPRIMITIVETYPE *primitive_type)
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4584 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4586 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4588 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4591 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4595 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4597 if(!This->stateBlock->vertexDecl) {
4598 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4599 return WINED3DERR_INVALIDCALL;
4602 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4603 if(This->stateBlock->streamIsUP) {
4604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4605 This->stateBlock->streamIsUP = FALSE;
4608 if(This->stateBlock->loadBaseVertexIndex != 0) {
4609 This->stateBlock->loadBaseVertexIndex = 0;
4610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4612 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4613 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4614 return WINED3D_OK;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 UINT idxStride = 2;
4621 IWineD3DBuffer *pIB;
4622 GLuint vbo;
4624 pIB = This->stateBlock->pIndexData;
4625 if (!pIB) {
4626 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4627 * without an index buffer set. (The first time at least...)
4628 * D3D8 simply dies, but I doubt it can do much harm to return
4629 * D3DERR_INVALIDCALL there as well. */
4630 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4631 return WINED3DERR_INVALIDCALL;
4634 if(!This->stateBlock->vertexDecl) {
4635 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4636 return WINED3DERR_INVALIDCALL;
4639 if(This->stateBlock->streamIsUP) {
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4641 This->stateBlock->streamIsUP = FALSE;
4643 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4645 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4647 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4648 idxStride = 2;
4649 } else {
4650 idxStride = 4;
4653 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4654 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4655 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4658 drawPrimitive(iface, index_count, startIndex, idxStride,
4659 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4661 return WINED3D_OK;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4665 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 IWineD3DBuffer *vb;
4670 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4671 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4673 if(!This->stateBlock->vertexDecl) {
4674 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4675 return WINED3DERR_INVALIDCALL;
4678 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4679 vb = This->stateBlock->streamSource[0];
4680 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4681 if (vb) IWineD3DBuffer_Release(vb);
4682 This->stateBlock->streamOffset[0] = 0;
4683 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4684 This->stateBlock->streamIsUP = TRUE;
4685 This->stateBlock->loadBaseVertexIndex = 0;
4687 /* TODO: Only mark dirty if drawing from a different UP address */
4688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4690 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4692 /* MSDN specifies stream zero settings must be set to NULL */
4693 This->stateBlock->streamStride[0] = 0;
4694 This->stateBlock->streamSource[0] = NULL;
4696 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4697 * the new stream sources or use UP drawing again
4699 return WINED3D_OK;
4702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4703 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4704 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4706 int idxStride;
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 IWineD3DBuffer *vb;
4709 IWineD3DBuffer *ib;
4711 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4712 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4714 if(!This->stateBlock->vertexDecl) {
4715 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4716 return WINED3DERR_INVALIDCALL;
4719 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4720 idxStride = 2;
4721 } else {
4722 idxStride = 4;
4725 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4726 vb = This->stateBlock->streamSource[0];
4727 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4728 if (vb) IWineD3DBuffer_Release(vb);
4729 This->stateBlock->streamIsUP = TRUE;
4730 This->stateBlock->streamOffset[0] = 0;
4731 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4733 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4734 This->stateBlock->baseVertexIndex = 0;
4735 This->stateBlock->loadBaseVertexIndex = 0;
4736 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4740 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4742 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4743 This->stateBlock->streamSource[0] = NULL;
4744 This->stateBlock->streamStride[0] = 0;
4745 ib = This->stateBlock->pIndexData;
4746 if(ib) {
4747 IWineD3DBuffer_Release(ib);
4748 This->stateBlock->pIndexData = NULL;
4750 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4751 * SetStreamSource to specify a vertex buffer
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4758 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4762 /* Mark the state dirty until we have nicer tracking
4763 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4764 * that value.
4766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4768 This->stateBlock->baseVertexIndex = 0;
4769 This->up_strided = DrawPrimStrideData;
4770 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4771 This->up_strided = NULL;
4772 return WINED3D_OK;
4775 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4776 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4777 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4780 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4782 /* Mark the state dirty until we have nicer tracking
4783 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4784 * that value.
4786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4788 This->stateBlock->streamIsUP = TRUE;
4789 This->stateBlock->baseVertexIndex = 0;
4790 This->up_strided = DrawPrimStrideData;
4791 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4792 This->up_strided = NULL;
4793 return WINED3D_OK;
4796 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4797 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4798 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4800 WINED3DLOCKED_BOX src;
4801 WINED3DLOCKED_BOX dst;
4802 HRESULT hr;
4804 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4805 iface, pSourceVolume, pDestinationVolume);
4807 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4808 * dirtification to improve loading performance.
4810 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4811 if(FAILED(hr)) return hr;
4812 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4813 if(FAILED(hr)) {
4814 IWineD3DVolume_UnlockBox(pSourceVolume);
4815 return hr;
4818 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4820 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4821 if(FAILED(hr)) {
4822 IWineD3DVolume_UnlockBox(pSourceVolume);
4823 } else {
4824 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4826 return hr;
4829 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4830 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4832 unsigned int level_count, i;
4833 WINED3DRESOURCETYPE type;
4834 HRESULT hr;
4836 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4838 /* Verify that the source and destination textures are non-NULL. */
4839 if (!src_texture || !dst_texture)
4841 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4842 return WINED3DERR_INVALIDCALL;
4845 if (src_texture == dst_texture)
4847 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4848 return WINED3DERR_INVALIDCALL;
4851 /* Verify that the source and destination textures are the same type. */
4852 type = IWineD3DBaseTexture_GetType(src_texture);
4853 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4855 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4856 return WINED3DERR_INVALIDCALL;
4859 /* Check that both textures have the identical numbers of levels. */
4860 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4861 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4863 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4864 return WINED3DERR_INVALIDCALL;
4867 /* Make sure that the destination texture is loaded. */
4868 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4870 /* Update every surface level of the texture. */
4871 switch (type)
4873 case WINED3DRTYPE_TEXTURE:
4875 IWineD3DSurface *src_surface;
4876 IWineD3DSurface *dst_surface;
4878 for (i = 0; i < level_count; ++i)
4880 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4881 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4882 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4883 IWineD3DSurface_Release(dst_surface);
4884 IWineD3DSurface_Release(src_surface);
4885 if (FAILED(hr))
4887 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4888 return hr;
4891 break;
4894 case WINED3DRTYPE_CUBETEXTURE:
4896 IWineD3DSurface *src_surface;
4897 IWineD3DSurface *dst_surface;
4898 WINED3DCUBEMAP_FACES face;
4900 for (i = 0; i < level_count; ++i)
4902 /* Update each cube face. */
4903 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4905 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4906 face, i, &src_surface);
4907 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4908 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4909 face, i, &dst_surface);
4910 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4911 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4912 IWineD3DSurface_Release(dst_surface);
4913 IWineD3DSurface_Release(src_surface);
4914 if (FAILED(hr))
4916 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4917 return hr;
4921 break;
4924 case WINED3DRTYPE_VOLUMETEXTURE:
4926 IWineD3DVolume *src_volume;
4927 IWineD3DVolume *dst_volume;
4929 for (i = 0; i < level_count; ++i)
4931 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4932 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4933 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4934 IWineD3DVolume_Release(dst_volume);
4935 IWineD3DVolume_Release(src_volume);
4936 if (FAILED(hr))
4938 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4939 return hr;
4942 break;
4945 default:
4946 FIXME("Unsupported texture type %#x.\n", type);
4947 return WINED3DERR_INVALIDCALL;
4950 return WINED3D_OK;
4953 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4954 IWineD3DSwapChain *swapChain;
4955 HRESULT hr;
4956 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4957 if(hr == WINED3D_OK) {
4958 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4959 IWineD3DSwapChain_Release(swapChain);
4961 return hr;
4964 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 IWineD3DBaseTextureImpl *texture;
4967 DWORD i;
4969 TRACE("(%p) : %p\n", This, pNumPasses);
4971 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4972 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4973 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4974 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4976 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4977 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4978 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4981 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4982 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4984 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4985 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4986 return E_FAIL;
4988 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4989 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4990 return E_FAIL;
4992 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4993 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4994 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4995 return E_FAIL;
4999 /* return a sensible default */
5000 *pNumPasses = 1;
5002 TRACE("returning D3D_OK\n");
5003 return WINED3D_OK;
5006 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5008 int i;
5010 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5012 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5013 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5014 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5016 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5021 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5023 int j;
5024 UINT NewSize;
5025 PALETTEENTRY **palettes;
5027 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5029 if (PaletteNumber >= MAX_PALETTES) {
5030 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5031 return WINED3DERR_INVALIDCALL;
5034 if (PaletteNumber >= This->NumberOfPalettes) {
5035 NewSize = This->NumberOfPalettes;
5036 do {
5037 NewSize *= 2;
5038 } while(PaletteNumber >= NewSize);
5039 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5040 if (!palettes) {
5041 ERR("Out of memory!\n");
5042 return E_OUTOFMEMORY;
5044 This->palettes = palettes;
5045 This->NumberOfPalettes = NewSize;
5048 if (!This->palettes[PaletteNumber]) {
5049 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5050 if (!This->palettes[PaletteNumber]) {
5051 ERR("Out of memory!\n");
5052 return E_OUTOFMEMORY;
5056 for (j = 0; j < 256; ++j) {
5057 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5058 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5059 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5060 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5062 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5063 TRACE("(%p) : returning\n", This);
5064 return WINED3D_OK;
5067 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5069 int j;
5070 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5071 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5072 /* What happens in such situation isn't documented; Native seems to silently abort
5073 on such conditions. Return Invalid Call. */
5074 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5075 return WINED3DERR_INVALIDCALL;
5077 for (j = 0; j < 256; ++j) {
5078 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5079 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5080 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5081 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5083 TRACE("(%p) : returning\n", This);
5084 return WINED3D_OK;
5087 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5090 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5091 (tested with reference rasterizer). Return Invalid Call. */
5092 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5093 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5094 return WINED3DERR_INVALIDCALL;
5096 /*TODO: stateblocks */
5097 if (This->currentPalette != PaletteNumber) {
5098 This->currentPalette = PaletteNumber;
5099 dirtify_p8_texture_samplers(This);
5101 TRACE("(%p) : returning\n", This);
5102 return WINED3D_OK;
5105 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5107 if (PaletteNumber == NULL) {
5108 WARN("(%p) : returning Invalid Call\n", This);
5109 return WINED3DERR_INVALIDCALL;
5111 /*TODO: stateblocks */
5112 *PaletteNumber = This->currentPalette;
5113 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5114 return WINED3D_OK;
5117 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 static BOOL warned;
5120 if (!warned)
5122 FIXME("(%p) : stub\n", This);
5123 warned = TRUE;
5126 This->softwareVertexProcessing = bSoftware;
5127 return WINED3D_OK;
5131 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 static BOOL warned;
5134 if (!warned)
5136 FIXME("(%p) : stub\n", This);
5137 warned = TRUE;
5139 return This->softwareVertexProcessing;
5142 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5143 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5145 IWineD3DSwapChain *swapchain;
5146 HRESULT hr;
5148 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5149 iface, swapchain_idx, raster_status);
5151 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5152 if (FAILED(hr))
5154 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5155 return hr;
5158 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5159 IWineD3DSwapChain_Release(swapchain);
5160 if (FAILED(hr))
5162 WARN("Failed to get raster status, hr %#x.\n", hr);
5163 return hr;
5166 return WINED3D_OK;
5169 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5171 static BOOL warned;
5172 if(nSegments != 0.0f) {
5173 if (!warned)
5175 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5176 warned = TRUE;
5179 return WINED3D_OK;
5182 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5184 static BOOL warned;
5185 if (!warned)
5187 FIXME("iface %p stub!\n", iface);
5188 warned = TRUE;
5190 return 0.0f;
5193 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5194 IWineD3DSurface *src_surface, const RECT *src_rect,
5195 IWineD3DSurface *dst_surface, const POINT *dst_point)
5197 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5198 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5200 const struct wined3d_format_desc *src_format;
5201 const struct wined3d_format_desc *dst_format;
5202 struct wined3d_context *context;
5203 const unsigned char *data;
5204 UINT update_w, update_h;
5205 CONVERT_TYPES convert;
5206 UINT src_w, src_h;
5207 UINT dst_x, dst_y;
5208 DWORD sampler;
5209 struct wined3d_format_desc dummy_desc;
5211 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s",
5212 iface, src_surface, wine_dbgstr_rect(src_rect),
5213 dst_surface, wine_dbgstr_point(dst_point));
5215 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5217 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5218 src_surface, dst_surface);
5219 return WINED3DERR_INVALIDCALL;
5222 src_format = src_impl->resource.format_desc;
5223 dst_format = dst_impl->resource.format_desc;
5225 if (src_format->format != dst_format->format)
5227 WARN("Source and destination surfaces should have the same format.\n");
5228 return WINED3DERR_INVALIDCALL;
5231 dst_x = dst_point ? dst_point->x : 0;
5232 dst_y = dst_point ? dst_point->y : 0;
5234 /* This call loads the OpenGL surface directly, instead of copying the
5235 * surface to the destination's sysmem copy. If surface conversion is
5236 * needed, use BltFast instead to copy in sysmem and use regular surface
5237 * loading. */
5238 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5239 if (convert != NO_CONVERSION)
5240 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5242 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5244 ENTER_GL();
5245 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5246 checkGLcall("glActiveTextureARB");
5247 LEAVE_GL();
5249 /* Make sure the surface is loaded and up to date */
5250 surface_internal_preload(dst_surface, SRGB_RGB);
5251 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5253 src_w = src_impl->currentDesc.Width;
5254 src_h = src_impl->currentDesc.Height;
5255 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5256 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5258 data = IWineD3DSurface_GetData(src_surface);
5259 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5261 ENTER_GL();
5263 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5265 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5266 UINT row_count = update_h / src_format->block_height;
5267 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5269 if (src_rect)
5271 data += (src_rect->top / src_format->block_height) * src_pitch;
5272 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5275 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5276 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5277 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5279 if (row_length == src_pitch)
5281 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5282 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5284 else
5286 UINT row, y;
5288 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5289 * can't use the unpack row length like below. */
5290 for (row = 0, y = dst_y; row < row_count; ++row)
5292 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5293 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5294 y += src_format->block_height;
5295 data += src_pitch;
5298 checkGLcall("glCompressedTexSubImage2DARB");
5300 else
5302 if (src_rect)
5304 data += src_rect->top * src_w * src_format->byte_count;
5305 data += src_rect->left * src_format->byte_count;
5308 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5309 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5310 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5312 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5313 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5314 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5315 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5316 checkGLcall("glTexSubImage2D");
5319 LEAVE_GL();
5320 context_release(context);
5322 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5323 sampler = This->rev_tex_unit_map[0];
5324 if (sampler != WINED3D_UNMAPPED_STAGE)
5326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5329 return WINED3D_OK;
5332 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5334 struct WineD3DRectPatch *patch;
5335 GLenum old_primitive_type;
5336 unsigned int i;
5337 struct list *e;
5338 BOOL found;
5339 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5341 if(!(Handle || pRectPatchInfo)) {
5342 /* TODO: Write a test for the return value, thus the FIXME */
5343 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5344 return WINED3DERR_INVALIDCALL;
5347 if(Handle) {
5348 i = PATCHMAP_HASHFUNC(Handle);
5349 found = FALSE;
5350 LIST_FOR_EACH(e, &This->patches[i]) {
5351 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5352 if(patch->Handle == Handle) {
5353 found = TRUE;
5354 break;
5358 if(!found) {
5359 TRACE("Patch does not exist. Creating a new one\n");
5360 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5361 patch->Handle = Handle;
5362 list_add_head(&This->patches[i], &patch->entry);
5363 } else {
5364 TRACE("Found existing patch %p\n", patch);
5366 } else {
5367 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5368 * attributes we have to tesselate, read back, and draw. This needs a patch
5369 * management structure instance. Create one.
5371 * A possible improvement is to check if a vertex shader is used, and if not directly
5372 * draw the patch.
5374 FIXME("Drawing an uncached patch. This is slow\n");
5375 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5378 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5379 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5380 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5381 HRESULT hr;
5382 TRACE("Tesselation density or patch info changed, retesselating\n");
5384 if(pRectPatchInfo) {
5385 patch->RectPatchInfo = *pRectPatchInfo;
5387 patch->numSegs[0] = pNumSegs[0];
5388 patch->numSegs[1] = pNumSegs[1];
5389 patch->numSegs[2] = pNumSegs[2];
5390 patch->numSegs[3] = pNumSegs[3];
5392 hr = tesselate_rectpatch(This, patch);
5393 if(FAILED(hr)) {
5394 WARN("Patch tesselation failed\n");
5396 /* Do not release the handle to store the params of the patch */
5397 if(!Handle) {
5398 HeapFree(GetProcessHeap(), 0, patch);
5400 return hr;
5404 This->currentPatch = patch;
5405 old_primitive_type = This->stateBlock->gl_primitive_type;
5406 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5407 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5408 This->stateBlock->gl_primitive_type = old_primitive_type;
5409 This->currentPatch = NULL;
5411 /* Destroy uncached patches */
5412 if(!Handle) {
5413 HeapFree(GetProcessHeap(), 0, patch->mem);
5414 HeapFree(GetProcessHeap(), 0, patch);
5416 return WINED3D_OK;
5419 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5420 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5422 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5423 iface, handle, segment_count, patch_info);
5425 return WINED3D_OK;
5428 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 int i;
5431 struct WineD3DRectPatch *patch;
5432 struct list *e;
5433 TRACE("(%p) Handle(%d)\n", This, Handle);
5435 i = PATCHMAP_HASHFUNC(Handle);
5436 LIST_FOR_EACH(e, &This->patches[i]) {
5437 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5438 if(patch->Handle == Handle) {
5439 TRACE("Deleting patch %p\n", patch);
5440 list_remove(&patch->entry);
5441 HeapFree(GetProcessHeap(), 0, patch->mem);
5442 HeapFree(GetProcessHeap(), 0, patch);
5443 return WINED3D_OK;
5447 /* TODO: Write a test for the return value */
5448 FIXME("Attempt to destroy nonexistent patch\n");
5449 return WINED3DERR_INVALIDCALL;
5452 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5453 const WINED3DRECT *rect, const float color[4])
5455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5456 struct wined3d_context *context;
5458 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5459 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5461 if (!surface_is_offscreen((IWineD3DSurfaceImpl *)surface))
5463 TRACE("Surface %p is onscreen\n", surface);
5465 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5466 ENTER_GL();
5467 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5468 context_set_draw_buffer(context, surface_get_gl_buffer((IWineD3DSurfaceImpl *)surface));
5470 else
5472 TRACE("Surface %p is offscreen\n", surface);
5474 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5475 ENTER_GL();
5476 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5477 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, (IWineD3DSurfaceImpl *)surface);
5478 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5481 if (rect) {
5482 glEnable(GL_SCISSOR_TEST);
5483 if (surface_is_offscreen((IWineD3DSurfaceImpl *)surface))
5484 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5485 else
5486 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5487 rect->x2 - rect->x1, rect->y2 - rect->y1);
5488 checkGLcall("glScissor");
5489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5490 } else {
5491 glDisable(GL_SCISSOR_TEST);
5493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5495 glDisable(GL_BLEND);
5496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5498 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5504 glClearColor(color[0], color[1], color[2], color[3]);
5505 glClear(GL_COLOR_BUFFER_BIT);
5506 checkGLcall("glClear");
5508 LEAVE_GL();
5510 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5512 context_release(context);
5515 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5516 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5518 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5519 WINEDDBLTFX BltFx;
5521 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5523 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5524 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5525 return WINED3DERR_INVALIDCALL;
5528 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5529 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5530 color_fill_fbo(iface, pSurface, pRect, c);
5531 return WINED3D_OK;
5532 } else {
5533 /* Just forward this to the DirectDraw blitting engine */
5534 memset(&BltFx, 0, sizeof(BltFx));
5535 BltFx.dwSize = sizeof(BltFx);
5536 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5537 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5538 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5542 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5543 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5545 IWineD3DResource *resource;
5546 IWineD3DSurface *surface;
5547 HRESULT hr;
5549 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5550 if (FAILED(hr))
5552 ERR("Failed to get resource, hr %#x\n", hr);
5553 return;
5556 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5558 FIXME("Only supported on surface resources\n");
5559 IWineD3DResource_Release(resource);
5560 return;
5563 surface = (IWineD3DSurface *)resource;
5565 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5567 color_fill_fbo(iface, surface, NULL, color);
5569 else
5571 WINEDDBLTFX BltFx;
5572 WINED3DCOLOR c;
5574 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5576 c = ((DWORD)(color[2] * 255.0f));
5577 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5578 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5579 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5581 /* Just forward this to the DirectDraw blitting engine */
5582 memset(&BltFx, 0, sizeof(BltFx));
5583 BltFx.dwSize = sizeof(BltFx);
5584 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5585 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5586 if (FAILED(hr))
5588 ERR("Blt failed, hr %#x\n", hr);
5592 IWineD3DResource_Release(resource);
5595 /* rendertarget and depth stencil functions */
5596 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5599 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5601 ERR("(%p) : Only %d render targets are supported.\n",
5602 This, This->adapter->gl_info.limits.buffers);
5603 return WINED3DERR_INVALIDCALL;
5606 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5607 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5608 /* Note inc ref on returned surface */
5609 if(*ppRenderTarget != NULL)
5610 IWineD3DSurface_AddRef(*ppRenderTarget);
5611 return WINED3D_OK;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5615 IWineD3DSurface *front, IWineD3DSurface *back)
5617 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5618 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5619 IWineD3DSwapChainImpl *swapchain;
5620 HRESULT hr;
5622 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5624 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5626 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5627 return hr;
5630 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5632 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5633 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5634 return WINED3DERR_INVALIDCALL;
5637 if (back_impl)
5639 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5641 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5642 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5643 return WINED3DERR_INVALIDCALL;
5646 if (!swapchain->backBuffer)
5648 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5649 if (!swapchain->backBuffer)
5651 ERR("Failed to allocate back buffer array memory.\n");
5652 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5653 return E_OUTOFMEMORY;
5658 if (swapchain->frontBuffer != front)
5660 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5662 if (swapchain->frontBuffer)
5664 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5665 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5667 swapchain->frontBuffer = front;
5669 if (front)
5671 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5672 front_impl->Flags |= SFLAG_SWAPCHAIN;
5676 if (swapchain->backBuffer[0] != back)
5678 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5680 if (swapchain->backBuffer[0])
5682 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5683 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5685 swapchain->backBuffer[0] = back;
5687 if (back)
5689 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5690 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5691 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5692 swapchain->presentParms.BackBufferCount = 1;
5694 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5695 back_impl->Flags |= SFLAG_SWAPCHAIN;
5697 else
5699 swapchain->presentParms.BackBufferCount = 0;
5700 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5701 swapchain->backBuffer = NULL;
5705 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5706 return WINED3D_OK;
5709 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5711 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5712 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5714 if(*ppZStencilSurface != NULL) {
5715 /* Note inc ref on returned surface */
5716 IWineD3DSurface_AddRef(*ppZStencilSurface);
5717 return WINED3D_OK;
5718 } else {
5719 return WINED3DERR_NOTFOUND;
5723 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5724 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5726 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5727 const struct wined3d_gl_info *gl_info;
5728 struct wined3d_context *context;
5729 GLenum gl_filter;
5730 POINT offset = {0, 0};
5731 RECT src_rect, dst_rect;
5733 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5734 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5735 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5737 src_rect = *src_rect_in;
5738 dst_rect = *dst_rect_in;
5740 switch (filter) {
5741 case WINED3DTEXF_LINEAR:
5742 gl_filter = GL_LINEAR;
5743 break;
5745 default:
5746 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5747 case WINED3DTEXF_NONE:
5748 case WINED3DTEXF_POINT:
5749 gl_filter = GL_NEAREST;
5750 break;
5753 /* Make sure the drawables are up-to-date. Note that loading the
5754 * destination surface isn't strictly required if we overwrite the
5755 * entire surface. */
5756 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5757 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5759 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, (IWineD3DSurface *)src_surface, CTXUSAGE_RESOURCELOAD);
5760 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, (IWineD3DSurface *)dst_surface, CTXUSAGE_RESOURCELOAD);
5761 else context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5763 if (!context->valid)
5765 context_release(context);
5766 WARN("Invalid context, skipping blit.\n");
5767 return;
5770 gl_info = context->gl_info;
5772 if (!surface_is_offscreen(src_surface))
5774 GLenum buffer = surface_get_gl_buffer(src_surface);
5776 TRACE("Source surface %p is onscreen\n", src_surface);
5778 if(buffer == GL_FRONT) {
5779 RECT windowsize;
5780 UINT h;
5781 ClientToScreen(context->win_handle, &offset);
5782 GetClientRect(context->win_handle, &windowsize);
5783 h = windowsize.bottom - windowsize.top;
5784 src_rect.left -= offset.x; src_rect.right -=offset.x;
5785 src_rect.top = offset.y + h - src_rect.top;
5786 src_rect.bottom = offset.y + h - src_rect.bottom;
5787 } else {
5788 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5789 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5792 ENTER_GL();
5793 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5794 glReadBuffer(buffer);
5795 checkGLcall("glReadBuffer()");
5796 } else {
5797 TRACE("Source surface %p is offscreen\n", src_surface);
5798 ENTER_GL();
5799 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5800 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5801 glReadBuffer(GL_COLOR_ATTACHMENT0);
5802 checkGLcall("glReadBuffer()");
5803 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5805 LEAVE_GL();
5807 /* Attach dst surface to dst fbo */
5808 if (!surface_is_offscreen(dst_surface))
5810 GLenum buffer = surface_get_gl_buffer(dst_surface);
5812 TRACE("Destination surface %p is onscreen\n", dst_surface);
5814 if(buffer == GL_FRONT) {
5815 RECT windowsize;
5816 UINT h;
5817 ClientToScreen(context->win_handle, &offset);
5818 GetClientRect(context->win_handle, &windowsize);
5819 h = windowsize.bottom - windowsize.top;
5820 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5821 dst_rect.top = offset.y + h - dst_rect.top;
5822 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5823 } else {
5824 /* Screen coords = window coords, surface height = window height */
5825 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5826 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5829 ENTER_GL();
5830 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5831 context_set_draw_buffer(context, buffer);
5833 else
5835 TRACE("Destination surface %p is offscreen\n", dst_surface);
5837 ENTER_GL();
5838 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5839 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5840 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5841 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5843 glDisable(GL_SCISSOR_TEST);
5844 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5846 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5847 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5848 checkGLcall("glBlitFramebuffer()");
5850 LEAVE_GL();
5852 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5854 context_release(context);
5856 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5859 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5860 BOOL set_viewport) {
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5865 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5867 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5868 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5869 return WINED3DERR_INVALIDCALL;
5872 /* MSDN says that null disables the render target
5873 but a device must always be associated with a render target
5874 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5876 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5877 FIXME("Trying to set render target 0 to NULL\n");
5878 return WINED3DERR_INVALIDCALL;
5880 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5881 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);
5882 return WINED3DERR_INVALIDCALL;
5885 /* If we are trying to set what we already have, don't bother */
5886 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5888 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5889 return WINED3D_OK;
5891 if (pRenderTarget)
5892 IWineD3DSurface_AddRef(pRenderTarget);
5893 if (This->render_targets[RenderTargetIndex])
5894 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5895 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5897 /* Render target 0 is special */
5898 if(RenderTargetIndex == 0 && set_viewport) {
5899 /* Finally, reset the viewport and scissor rect as the MSDN states.
5900 * Tests show that stateblock recording is ignored, the change goes
5901 * directly into the primary stateblock.
5903 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5904 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5905 This->stateBlock->viewport.X = 0;
5906 This->stateBlock->viewport.Y = 0;
5907 This->stateBlock->viewport.MaxZ = 1.0f;
5908 This->stateBlock->viewport.MinZ = 0.0f;
5909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5911 This->stateBlock->scissorRect.top = 0;
5912 This->stateBlock->scissorRect.left = 0;
5913 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5914 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5917 return WINED3D_OK;
5920 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5922 IWineD3DSurfaceImpl *tmp;
5924 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5926 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5928 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5929 return WINED3D_OK;
5932 if (This->depth_stencil)
5934 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5935 || This->depth_stencil->Flags & SFLAG_DISCARD)
5937 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED);
5938 if (This->depth_stencil == This->onscreen_depth_stencil)
5940 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5941 This->onscreen_depth_stencil = NULL;
5946 tmp = This->depth_stencil;
5947 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5948 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5949 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5951 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5953 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5959 return WINED3D_OK;
5962 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5963 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5965 /* TODO: the use of Impl is deprecated. */
5966 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5967 WINED3DLOCKED_RECT lockedRect;
5969 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5971 /* some basic validation checks */
5972 if(This->cursorTexture) {
5973 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5974 ENTER_GL();
5975 glDeleteTextures(1, &This->cursorTexture);
5976 LEAVE_GL();
5977 context_release(context);
5978 This->cursorTexture = 0;
5981 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5982 This->haveHardwareCursor = TRUE;
5983 else
5984 This->haveHardwareCursor = FALSE;
5986 if(pCursorBitmap) {
5987 WINED3DLOCKED_RECT rect;
5989 /* MSDN: Cursor must be A8R8G8B8 */
5990 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5992 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5993 return WINED3DERR_INVALIDCALL;
5996 /* MSDN: Cursor must be smaller than the display mode */
5997 if(pSur->currentDesc.Width > This->ddraw_width ||
5998 pSur->currentDesc.Height > This->ddraw_height) {
5999 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);
6000 return WINED3DERR_INVALIDCALL;
6003 if (!This->haveHardwareCursor) {
6004 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6006 /* Do not store the surface's pointer because the application may
6007 * release it after setting the cursor image. Windows doesn't
6008 * addref the set surface, so we can't do this either without
6009 * creating circular refcount dependencies. Copy out the gl texture
6010 * instead.
6012 This->cursorWidth = pSur->currentDesc.Width;
6013 This->cursorHeight = pSur->currentDesc.Height;
6014 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6016 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6017 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6018 struct wined3d_context *context;
6019 char *mem, *bits = rect.pBits;
6020 GLint intfmt = format_desc->glInternal;
6021 GLint format = format_desc->glFormat;
6022 GLint type = format_desc->glType;
6023 INT height = This->cursorHeight;
6024 INT width = This->cursorWidth;
6025 INT bpp = format_desc->byte_count;
6026 DWORD sampler;
6027 INT i;
6029 /* Reformat the texture memory (pitch and width can be
6030 * different) */
6031 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6032 for(i = 0; i < height; i++)
6033 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6034 IWineD3DSurface_UnlockRect(pCursorBitmap);
6036 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6038 ENTER_GL();
6040 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6042 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6043 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6046 /* Make sure that a proper texture unit is selected */
6047 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6048 checkGLcall("glActiveTextureARB");
6049 sampler = This->rev_tex_unit_map[0];
6050 if (sampler != WINED3D_UNMAPPED_STAGE)
6052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6054 /* Create a new cursor texture */
6055 glGenTextures(1, &This->cursorTexture);
6056 checkGLcall("glGenTextures");
6057 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6058 checkGLcall("glBindTexture");
6059 /* Copy the bitmap memory into the cursor texture */
6060 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6061 HeapFree(GetProcessHeap(), 0, mem);
6062 checkGLcall("glTexImage2D");
6064 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6066 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6067 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6070 LEAVE_GL();
6072 context_release(context);
6074 else
6076 FIXME("A cursor texture was not returned.\n");
6077 This->cursorTexture = 0;
6080 else
6082 /* Draw a hardware cursor */
6083 ICONINFO cursorInfo;
6084 HCURSOR cursor;
6085 /* Create and clear maskBits because it is not needed for
6086 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6087 * chunks. */
6088 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6089 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6090 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6091 WINED3DLOCK_NO_DIRTY_UPDATE |
6092 WINED3DLOCK_READONLY
6094 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6095 pSur->currentDesc.Height);
6097 cursorInfo.fIcon = FALSE;
6098 cursorInfo.xHotspot = XHotSpot;
6099 cursorInfo.yHotspot = YHotSpot;
6100 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6101 1, 1, maskBits);
6102 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6103 1, 32, lockedRect.pBits);
6104 IWineD3DSurface_UnlockRect(pCursorBitmap);
6105 /* Create our cursor and clean up. */
6106 cursor = CreateIconIndirect(&cursorInfo);
6107 SetCursor(cursor);
6108 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6109 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6110 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6111 This->hardwareCursor = cursor;
6112 HeapFree(GetProcessHeap(), 0, maskBits);
6116 This->xHotSpot = XHotSpot;
6117 This->yHotSpot = YHotSpot;
6118 return WINED3D_OK;
6121 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6123 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6125 This->xScreenSpace = XScreenSpace;
6126 This->yScreenSpace = YScreenSpace;
6128 return;
6132 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6134 BOOL oldVisible = This->bCursorVisible;
6135 POINT pt;
6137 TRACE("(%p) : visible(%d)\n", This, bShow);
6140 * When ShowCursor is first called it should make the cursor appear at the OS's last
6141 * known cursor position. Because of this, some applications just repetitively call
6142 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6144 GetCursorPos(&pt);
6145 This->xScreenSpace = pt.x;
6146 This->yScreenSpace = pt.y;
6148 if (This->haveHardwareCursor) {
6149 This->bCursorVisible = bShow;
6150 if (bShow)
6151 SetCursor(This->hardwareCursor);
6152 else
6153 SetCursor(NULL);
6155 else
6157 if (This->cursorTexture)
6158 This->bCursorVisible = bShow;
6161 return oldVisible;
6164 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6165 TRACE("checking resource %p for eviction\n", resource);
6166 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6167 TRACE("Evicting %p\n", resource);
6168 IWineD3DResource_UnLoad(resource);
6170 IWineD3DResource_Release(resource);
6171 return S_OK;
6174 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6176 TRACE("iface %p.\n", iface);
6178 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6179 return WINED3D_OK;
6182 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6184 IWineD3DDeviceImpl *device = surface->resource.device;
6185 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6187 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6188 if(surface->Flags & SFLAG_DIBSECTION) {
6189 /* Release the DC */
6190 SelectObject(surface->hDC, surface->dib.holdbitmap);
6191 DeleteDC(surface->hDC);
6192 /* Release the DIB section */
6193 DeleteObject(surface->dib.DIBsection);
6194 surface->dib.bitmap_data = NULL;
6195 surface->resource.allocatedMemory = NULL;
6196 surface->Flags &= ~SFLAG_DIBSECTION;
6198 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6199 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6200 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6201 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6203 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6204 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6205 } else {
6206 surface->pow2Width = surface->pow2Height = 1;
6207 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6208 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6211 if (surface->texture_name)
6213 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6214 ENTER_GL();
6215 glDeleteTextures(1, &surface->texture_name);
6216 LEAVE_GL();
6217 context_release(context);
6218 surface->texture_name = 0;
6219 surface->Flags &= ~SFLAG_CLIENT;
6221 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6222 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6223 surface->Flags |= SFLAG_NONPOW2;
6224 } else {
6225 surface->Flags &= ~SFLAG_NONPOW2;
6227 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6228 surface->resource.allocatedMemory = NULL;
6229 surface->resource.heapMemory = NULL;
6230 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6232 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6233 * to a FBO */
6234 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6236 return E_OUTOFMEMORY;
6238 return WINED3D_OK;
6241 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6242 TRACE("Unloading resource %p\n", resource);
6243 IWineD3DResource_UnLoad(resource);
6244 IWineD3DResource_Release(resource);
6245 return S_OK;
6248 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6250 UINT i, count;
6251 WINED3DDISPLAYMODE m;
6252 HRESULT hr;
6254 /* All Windowed modes are supported, as is leaving the current mode */
6255 if(pp->Windowed) return TRUE;
6256 if(!pp->BackBufferWidth) return TRUE;
6257 if(!pp->BackBufferHeight) return TRUE;
6259 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6260 for(i = 0; i < count; i++) {
6261 memset(&m, 0, sizeof(m));
6262 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6263 if(FAILED(hr)) {
6264 ERR("EnumAdapterModes failed\n");
6266 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6267 /* Mode found, it is supported */
6268 return TRUE;
6271 /* Mode not found -> not supported */
6272 return FALSE;
6275 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6278 const struct wined3d_gl_info *gl_info;
6279 struct wined3d_context *context;
6280 IWineD3DBaseShaderImpl *shader;
6282 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6283 gl_info = context->gl_info;
6285 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6286 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6287 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6290 ENTER_GL();
6291 if(This->depth_blt_texture) {
6292 glDeleteTextures(1, &This->depth_blt_texture);
6293 This->depth_blt_texture = 0;
6295 if (This->depth_blt_rb) {
6296 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6297 This->depth_blt_rb = 0;
6298 This->depth_blt_rb_w = 0;
6299 This->depth_blt_rb_h = 0;
6301 LEAVE_GL();
6303 This->blitter->free_private(iface);
6304 This->frag_pipe->free_private(iface);
6305 This->shader_backend->shader_free_private(iface);
6306 destroy_dummy_textures(This, gl_info);
6308 context_release(context);
6310 while (This->numContexts)
6312 context_destroy(This, This->contexts[0]);
6314 HeapFree(GetProcessHeap(), 0, swapchain->context);
6315 swapchain->context = NULL;
6316 swapchain->num_contexts = 0;
6319 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6322 struct wined3d_context *context;
6323 HRESULT hr;
6324 IWineD3DSurfaceImpl *target;
6326 /* Recreate the primary swapchain's context */
6327 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6328 if (!swapchain->context)
6330 ERR("Failed to allocate memory for swapchain context array.\n");
6331 return E_OUTOFMEMORY;
6334 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6335 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6337 WARN("Failed to create context.\n");
6338 HeapFree(GetProcessHeap(), 0, swapchain->context);
6339 return E_FAIL;
6342 swapchain->context[0] = context;
6343 swapchain->num_contexts = 1;
6344 create_dummy_textures(This);
6345 context_release(context);
6347 hr = This->shader_backend->shader_alloc_private(iface);
6348 if (FAILED(hr))
6350 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6351 goto err;
6354 hr = This->frag_pipe->alloc_private(iface);
6355 if (FAILED(hr))
6357 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6358 This->shader_backend->shader_free_private(iface);
6359 goto err;
6362 hr = This->blitter->alloc_private(iface);
6363 if (FAILED(hr))
6365 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6366 This->frag_pipe->free_private(iface);
6367 This->shader_backend->shader_free_private(iface);
6368 goto err;
6371 return WINED3D_OK;
6373 err:
6374 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6375 destroy_dummy_textures(This, context->gl_info);
6376 context_release(context);
6377 context_destroy(This, context);
6378 HeapFree(GetProcessHeap(), 0, swapchain->context);
6379 swapchain->num_contexts = 0;
6380 return hr;
6383 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6385 IWineD3DSwapChainImpl *swapchain;
6386 HRESULT hr;
6387 BOOL DisplayModeChanged = FALSE;
6388 WINED3DDISPLAYMODE mode;
6389 TRACE("(%p)\n", This);
6391 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6392 if(FAILED(hr)) {
6393 ERR("Failed to get the first implicit swapchain\n");
6394 return hr;
6397 if(!is_display_mode_supported(This, pPresentationParameters)) {
6398 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6399 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6400 pPresentationParameters->BackBufferHeight);
6401 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6402 return WINED3DERR_INVALIDCALL;
6405 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6406 * on an existing gl context, so there's no real need for recreation.
6408 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6410 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6412 TRACE("New params:\n");
6413 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6414 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6415 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6416 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6417 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6418 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6419 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6420 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6421 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6422 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6423 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6424 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6425 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6427 /* No special treatment of these parameters. Just store them */
6428 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6429 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6430 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6431 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6433 /* What to do about these? */
6434 if(pPresentationParameters->BackBufferCount != 0 &&
6435 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6436 ERR("Cannot change the back buffer count yet\n");
6438 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6439 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6440 ERR("Cannot change the back buffer format yet\n");
6442 if(pPresentationParameters->hDeviceWindow != NULL &&
6443 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6444 ERR("Cannot change the device window yet\n");
6446 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6448 HRESULT hrc;
6450 TRACE("Creating the depth stencil buffer\n");
6452 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6453 This->parent,
6454 pPresentationParameters->BackBufferWidth,
6455 pPresentationParameters->BackBufferHeight,
6456 pPresentationParameters->AutoDepthStencilFormat,
6457 pPresentationParameters->MultiSampleType,
6458 pPresentationParameters->MultiSampleQuality,
6459 FALSE,
6460 (IWineD3DSurface **)&This->auto_depth_stencil);
6462 if (FAILED(hrc)) {
6463 ERR("Failed to create the depth stencil buffer\n");
6464 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6465 return WINED3DERR_INVALIDCALL;
6469 if (This->onscreen_depth_stencil)
6471 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6472 This->onscreen_depth_stencil = NULL;
6475 /* Reset the depth stencil */
6476 if (pPresentationParameters->EnableAutoDepthStencil)
6477 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6478 else
6479 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6481 TRACE("Resetting stateblock\n");
6482 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6483 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6485 delete_opengl_contexts(iface, swapchain);
6487 if(pPresentationParameters->Windowed) {
6488 mode.Width = swapchain->orig_width;
6489 mode.Height = swapchain->orig_height;
6490 mode.RefreshRate = 0;
6491 mode.Format = swapchain->presentParms.BackBufferFormat;
6492 } else {
6493 mode.Width = pPresentationParameters->BackBufferWidth;
6494 mode.Height = pPresentationParameters->BackBufferHeight;
6495 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6496 mode.Format = swapchain->presentParms.BackBufferFormat;
6499 /* Should Width == 800 && Height == 0 set 800x600? */
6500 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6501 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6502 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6504 UINT i;
6506 if(!pPresentationParameters->Windowed) {
6507 DisplayModeChanged = TRUE;
6509 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6510 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6512 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6513 if(FAILED(hr))
6515 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6516 return hr;
6519 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6520 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6521 if(FAILED(hr))
6523 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6524 return hr;
6527 if (This->auto_depth_stencil)
6529 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6530 if(FAILED(hr))
6532 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6533 return hr;
6538 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6539 || DisplayModeChanged)
6541 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6543 if (!pPresentationParameters->Windowed)
6545 if(swapchain->presentParms.Windowed) {
6546 /* switch from windowed to fs */
6547 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6548 pPresentationParameters->BackBufferHeight);
6549 } else {
6550 /* Fullscreen -> fullscreen mode change */
6551 MoveWindow(swapchain->device_window, 0, 0,
6552 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6553 TRUE);
6556 else if (!swapchain->presentParms.Windowed)
6558 /* Fullscreen -> windowed switch */
6559 swapchain_restore_fullscreen_window(swapchain);
6561 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6562 } else if(!pPresentationParameters->Windowed) {
6563 DWORD style = This->style, exStyle = This->exStyle;
6564 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6565 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6566 * Reset to clear up their mess. Guild Wars also loses the device during that.
6568 This->style = 0;
6569 This->exStyle = 0;
6570 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6571 pPresentationParameters->BackBufferHeight);
6572 This->style = style;
6573 This->exStyle = exStyle;
6576 /* Note: No parent needed for initial internal stateblock */
6577 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6578 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6579 else TRACE("Created stateblock %p\n", This->stateBlock);
6580 This->updateStateBlock = This->stateBlock;
6581 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6583 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6584 if(FAILED(hr)) {
6585 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6588 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6590 RECT client_rect;
6591 GetClientRect(swapchain->win_handle, &client_rect);
6593 if(!swapchain->presentParms.BackBufferCount)
6595 TRACE("Single buffered rendering\n");
6596 swapchain->render_to_fbo = FALSE;
6598 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6599 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6601 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6602 swapchain->presentParms.BackBufferWidth,
6603 swapchain->presentParms.BackBufferHeight,
6604 client_rect.right, client_rect.bottom);
6605 swapchain->render_to_fbo = TRUE;
6607 else
6609 TRACE("Rendering directly to GL_BACK\n");
6610 swapchain->render_to_fbo = FALSE;
6614 hr = create_primary_opengl_context(iface, swapchain);
6615 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6617 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6618 * first use
6620 return hr;
6623 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6625 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6627 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6629 return WINED3D_OK;
6633 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6635 TRACE("(%p) : pParameters %p\n", This, pParameters);
6637 *pParameters = This->createParms;
6638 return WINED3D_OK;
6641 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6642 IWineD3DSwapChain *swapchain;
6644 TRACE("Relaying to swapchain\n");
6646 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6647 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6648 IWineD3DSwapChain_Release(swapchain);
6652 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6653 IWineD3DSwapChain *swapchain;
6655 TRACE("Relaying to swapchain\n");
6657 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6658 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6659 IWineD3DSwapChain_Release(swapchain);
6664 /** ********************************************************
6665 * Notification functions
6666 ** ********************************************************/
6667 /** This function must be called in the release of a resource when ref == 0,
6668 * the contents of resource must still be correct,
6669 * any handles to other resource held by the caller must be closed
6670 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6671 *****************************************************/
6672 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6674 TRACE("(%p) : Adding resource %p\n", This, resource);
6676 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6679 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6681 TRACE("(%p) : Removing resource %p\n", This, resource);
6683 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6686 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6688 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6689 int counter;
6691 TRACE("(%p) : resource %p\n", This, resource);
6693 context_resource_released((IWineD3DDevice *)This, resource, type);
6695 switch (type) {
6696 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6697 case WINED3DRTYPE_SURFACE: {
6698 unsigned int i;
6700 if (This->d3d_initialized)
6702 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6704 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6705 This->render_targets[i] = NULL;
6707 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6708 This->depth_stencil = NULL;
6711 break;
6713 case WINED3DRTYPE_TEXTURE:
6714 case WINED3DRTYPE_CUBETEXTURE:
6715 case WINED3DRTYPE_VOLUMETEXTURE:
6716 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6717 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6718 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6719 This->stateBlock->textures[counter] = NULL;
6721 if (This->updateStateBlock != This->stateBlock ){
6722 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6723 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6724 This->updateStateBlock->textures[counter] = NULL;
6728 break;
6729 case WINED3DRTYPE_VOLUME:
6730 /* TODO: nothing really? */
6731 break;
6732 case WINED3DRTYPE_BUFFER:
6734 int streamNumber;
6735 TRACE("Cleaning up stream pointers\n");
6737 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6738 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6739 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6741 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6742 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6743 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6744 This->updateStateBlock->streamSource[streamNumber] = 0;
6745 /* Set changed flag? */
6748 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) */
6749 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6750 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6751 This->stateBlock->streamSource[streamNumber] = 0;
6756 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6757 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6758 This->updateStateBlock->pIndexData = NULL;
6761 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6762 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6763 This->stateBlock->pIndexData = NULL;
6767 break;
6769 default:
6770 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6771 break;
6775 /* Remove the resource from the resourceStore */
6776 device_resource_remove(This, resource);
6778 TRACE("Resource released\n");
6782 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 IWineD3DResourceImpl *resource, *cursor;
6785 HRESULT ret;
6786 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6788 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6789 TRACE("enumerating resource %p\n", resource);
6790 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6791 ret = pCallback((IWineD3DResource *) resource, pData);
6792 if(ret == S_FALSE) {
6793 TRACE("Canceling enumeration\n");
6794 break;
6797 return WINED3D_OK;
6800 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6803 IWineD3DResourceImpl *resource;
6805 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6807 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6808 if (type == WINED3DRTYPE_SURFACE)
6810 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6812 TRACE("Found surface %p for dc %p.\n", resource, dc);
6813 *surface = (IWineD3DSurface *)resource;
6814 return WINED3D_OK;
6819 return WINED3DERR_INVALIDCALL;
6822 /**********************************************************
6823 * IWineD3DDevice VTbl follows
6824 **********************************************************/
6826 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6828 /*** IUnknown methods ***/
6829 IWineD3DDeviceImpl_QueryInterface,
6830 IWineD3DDeviceImpl_AddRef,
6831 IWineD3DDeviceImpl_Release,
6832 /*** IWineD3DDevice methods ***/
6833 IWineD3DDeviceImpl_GetParent,
6834 /*** Creation methods**/
6835 IWineD3DDeviceImpl_CreateBuffer,
6836 IWineD3DDeviceImpl_CreateVertexBuffer,
6837 IWineD3DDeviceImpl_CreateIndexBuffer,
6838 IWineD3DDeviceImpl_CreateStateBlock,
6839 IWineD3DDeviceImpl_CreateSurface,
6840 IWineD3DDeviceImpl_CreateRendertargetView,
6841 IWineD3DDeviceImpl_CreateTexture,
6842 IWineD3DDeviceImpl_CreateVolumeTexture,
6843 IWineD3DDeviceImpl_CreateVolume,
6844 IWineD3DDeviceImpl_CreateCubeTexture,
6845 IWineD3DDeviceImpl_CreateQuery,
6846 IWineD3DDeviceImpl_CreateSwapChain,
6847 IWineD3DDeviceImpl_CreateVertexDeclaration,
6848 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6849 IWineD3DDeviceImpl_CreateVertexShader,
6850 IWineD3DDeviceImpl_CreateGeometryShader,
6851 IWineD3DDeviceImpl_CreatePixelShader,
6852 IWineD3DDeviceImpl_CreatePalette,
6853 /*** Odd functions **/
6854 IWineD3DDeviceImpl_Init3D,
6855 IWineD3DDeviceImpl_InitGDI,
6856 IWineD3DDeviceImpl_Uninit3D,
6857 IWineD3DDeviceImpl_UninitGDI,
6858 IWineD3DDeviceImpl_SetMultithreaded,
6859 IWineD3DDeviceImpl_EvictManagedResources,
6860 IWineD3DDeviceImpl_GetAvailableTextureMem,
6861 IWineD3DDeviceImpl_GetBackBuffer,
6862 IWineD3DDeviceImpl_GetCreationParameters,
6863 IWineD3DDeviceImpl_GetDeviceCaps,
6864 IWineD3DDeviceImpl_GetDirect3D,
6865 IWineD3DDeviceImpl_GetDisplayMode,
6866 IWineD3DDeviceImpl_SetDisplayMode,
6867 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6868 IWineD3DDeviceImpl_GetRasterStatus,
6869 IWineD3DDeviceImpl_GetSwapChain,
6870 IWineD3DDeviceImpl_Reset,
6871 IWineD3DDeviceImpl_SetDialogBoxMode,
6872 IWineD3DDeviceImpl_SetCursorProperties,
6873 IWineD3DDeviceImpl_SetCursorPosition,
6874 IWineD3DDeviceImpl_ShowCursor,
6875 /*** Getters and setters **/
6876 IWineD3DDeviceImpl_SetClipPlane,
6877 IWineD3DDeviceImpl_GetClipPlane,
6878 IWineD3DDeviceImpl_SetClipStatus,
6879 IWineD3DDeviceImpl_GetClipStatus,
6880 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6881 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6882 IWineD3DDeviceImpl_SetDepthStencilSurface,
6883 IWineD3DDeviceImpl_GetDepthStencilSurface,
6884 IWineD3DDeviceImpl_SetGammaRamp,
6885 IWineD3DDeviceImpl_GetGammaRamp,
6886 IWineD3DDeviceImpl_SetIndexBuffer,
6887 IWineD3DDeviceImpl_GetIndexBuffer,
6888 IWineD3DDeviceImpl_SetBaseVertexIndex,
6889 IWineD3DDeviceImpl_GetBaseVertexIndex,
6890 IWineD3DDeviceImpl_SetLight,
6891 IWineD3DDeviceImpl_GetLight,
6892 IWineD3DDeviceImpl_SetLightEnable,
6893 IWineD3DDeviceImpl_GetLightEnable,
6894 IWineD3DDeviceImpl_SetMaterial,
6895 IWineD3DDeviceImpl_GetMaterial,
6896 IWineD3DDeviceImpl_SetNPatchMode,
6897 IWineD3DDeviceImpl_GetNPatchMode,
6898 IWineD3DDeviceImpl_SetPaletteEntries,
6899 IWineD3DDeviceImpl_GetPaletteEntries,
6900 IWineD3DDeviceImpl_SetPixelShader,
6901 IWineD3DDeviceImpl_GetPixelShader,
6902 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6903 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6904 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6905 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6906 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6907 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6908 IWineD3DDeviceImpl_SetRenderState,
6909 IWineD3DDeviceImpl_GetRenderState,
6910 IWineD3DDeviceImpl_SetRenderTarget,
6911 IWineD3DDeviceImpl_GetRenderTarget,
6912 IWineD3DDeviceImpl_SetFrontBackBuffers,
6913 IWineD3DDeviceImpl_SetSamplerState,
6914 IWineD3DDeviceImpl_GetSamplerState,
6915 IWineD3DDeviceImpl_SetScissorRect,
6916 IWineD3DDeviceImpl_GetScissorRect,
6917 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6918 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6919 IWineD3DDeviceImpl_SetStreamSource,
6920 IWineD3DDeviceImpl_GetStreamSource,
6921 IWineD3DDeviceImpl_SetStreamSourceFreq,
6922 IWineD3DDeviceImpl_GetStreamSourceFreq,
6923 IWineD3DDeviceImpl_SetTexture,
6924 IWineD3DDeviceImpl_GetTexture,
6925 IWineD3DDeviceImpl_SetTextureStageState,
6926 IWineD3DDeviceImpl_GetTextureStageState,
6927 IWineD3DDeviceImpl_SetTransform,
6928 IWineD3DDeviceImpl_GetTransform,
6929 IWineD3DDeviceImpl_SetVertexDeclaration,
6930 IWineD3DDeviceImpl_GetVertexDeclaration,
6931 IWineD3DDeviceImpl_SetVertexShader,
6932 IWineD3DDeviceImpl_GetVertexShader,
6933 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6934 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6935 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6936 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6939 IWineD3DDeviceImpl_SetViewport,
6940 IWineD3DDeviceImpl_GetViewport,
6941 IWineD3DDeviceImpl_MultiplyTransform,
6942 IWineD3DDeviceImpl_ValidateDevice,
6943 IWineD3DDeviceImpl_ProcessVertices,
6944 /*** State block ***/
6945 IWineD3DDeviceImpl_BeginStateBlock,
6946 IWineD3DDeviceImpl_EndStateBlock,
6947 /*** Scene management ***/
6948 IWineD3DDeviceImpl_BeginScene,
6949 IWineD3DDeviceImpl_EndScene,
6950 IWineD3DDeviceImpl_Present,
6951 IWineD3DDeviceImpl_Clear,
6952 IWineD3DDeviceImpl_ClearRendertargetView,
6953 /*** Drawing ***/
6954 IWineD3DDeviceImpl_SetPrimitiveType,
6955 IWineD3DDeviceImpl_GetPrimitiveType,
6956 IWineD3DDeviceImpl_DrawPrimitive,
6957 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6958 IWineD3DDeviceImpl_DrawPrimitiveUP,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6960 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6962 IWineD3DDeviceImpl_DrawRectPatch,
6963 IWineD3DDeviceImpl_DrawTriPatch,
6964 IWineD3DDeviceImpl_DeletePatch,
6965 IWineD3DDeviceImpl_ColorFill,
6966 IWineD3DDeviceImpl_UpdateTexture,
6967 IWineD3DDeviceImpl_UpdateSurface,
6968 IWineD3DDeviceImpl_GetFrontBufferData,
6969 /*** object tracking ***/
6970 IWineD3DDeviceImpl_EnumResources,
6971 IWineD3DDeviceImpl_GetSurfaceFromDC,
6972 IWineD3DDeviceImpl_AcquireFocusWindow,
6973 IWineD3DDeviceImpl_ReleaseFocusWindow,
6976 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6977 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6978 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6980 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6981 const struct fragment_pipeline *fragment_pipeline;
6982 struct shader_caps shader_caps;
6983 struct fragment_caps ffp_caps;
6984 WINED3DDISPLAYMODE mode;
6985 unsigned int i;
6986 HRESULT hr;
6988 device->lpVtbl = &IWineD3DDevice_Vtbl;
6989 device->ref = 1;
6990 device->wined3d = (IWineD3D *)wined3d;
6991 IWineD3D_AddRef(device->wined3d);
6992 device->adapter = wined3d->adapter_count ? adapter : NULL;
6993 device->parent = parent;
6994 device->device_parent = device_parent;
6995 list_init(&device->resources);
6996 list_init(&device->shaders);
6998 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6999 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7001 /* Get the initial screen setup for ddraw. */
7002 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7003 if (FAILED(hr))
7005 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7006 IWineD3D_Release(device->wined3d);
7007 return hr;
7009 device->ddraw_width = mode.Width;
7010 device->ddraw_height = mode.Height;
7011 device->ddraw_format = mode.Format;
7013 /* Save the creation parameters. */
7014 device->createParms.AdapterOrdinal = adapter_idx;
7015 device->createParms.DeviceType = device_type;
7016 device->createParms.hFocusWindow = focus_window;
7017 device->createParms.BehaviorFlags = flags;
7019 device->devType = device_type;
7020 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7022 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7023 device->shader_backend = adapter->shader_backend;
7025 memset(&shader_caps, 0, sizeof(shader_caps));
7026 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7027 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7028 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7029 device->vs_clipping = shader_caps.VSClipping;
7031 memset(&ffp_caps, 0, sizeof(ffp_caps));
7032 fragment_pipeline = adapter->fragment_pipe;
7033 device->frag_pipe = fragment_pipeline;
7034 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7035 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7037 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7038 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7039 if (FAILED(hr))
7041 ERR("Failed to compile state table, hr %#x.\n", hr);
7042 IWineD3D_Release(device->wined3d);
7043 return hr;
7046 device->blitter = adapter->blitter;
7048 return WINED3D_OK;
7052 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7053 DWORD rep = This->StateTable[state].representative;
7054 struct wined3d_context *context;
7055 DWORD idx;
7056 BYTE shift;
7057 UINT i;
7059 for(i = 0; i < This->numContexts; i++) {
7060 context = This->contexts[i];
7061 if(isStateDirty(context, rep)) continue;
7063 context->dirtyArray[context->numDirtyEntries++] = rep;
7064 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7065 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7066 context->isStateDirty[idx] |= (1 << shift);
7070 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7072 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7073 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7074 *width = surface->pow2Width;
7075 *height = surface->pow2Height;
7078 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7080 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7081 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7082 * current context's drawable, which is the size of the back buffer of the swapchain
7083 * the active context belongs to. */
7084 *width = swapchain->presentParms.BackBufferWidth;
7085 *height = swapchain->presentParms.BackBufferHeight;
7088 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7089 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7091 if (device->filter_messages)
7093 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7094 window, message, wparam, lparam);
7095 return DefWindowProcW(window, message, wparam, lparam);
7098 if (message == WM_DESTROY)
7100 TRACE("unregister window %p.\n", window);
7101 wined3d_unregister_window(window);
7103 if (device->focus_window == window) device->focus_window = NULL;
7104 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7107 return CallWindowProcW(proc, window, message, wparam, lparam);