comdlg32: Fix some alignment issues in the Dutch translation.
[wine/hramrach.git] / dlls / wined3d / device.c
blob3001b3b190039080fcbe4ccd1a6e4d4ab167100e
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_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
568 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
569 WINED3DVIEWPORT *vp = &stateblock->viewport;
571 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
573 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
575 IntersectRect(rect, rect, &stateblock->scissorRect);
579 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
580 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
582 if (device->onscreen_depth_stencil)
584 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
585 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
586 device->onscreen_depth_stencil->ds_current_size.cx,
587 device->onscreen_depth_stencil->ds_current_size.cy);
588 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
590 device->onscreen_depth_stencil = depth_stencil;
591 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
594 /**********************************************************
595 * IUnknown parts follows
596 **********************************************************/
598 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
602 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
603 if (IsEqualGUID(riid, &IID_IUnknown)
604 || IsEqualGUID(riid, &IID_IWineD3DBase)
605 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
606 IUnknown_AddRef(iface);
607 *ppobj = This;
608 return S_OK;
610 *ppobj = NULL;
611 return E_NOINTERFACE;
614 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
616 ULONG refCount = InterlockedIncrement(&This->ref);
618 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
619 return refCount;
622 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
624 ULONG refCount = InterlockedDecrement(&This->ref);
626 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
628 if (!refCount) {
629 UINT i;
631 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
632 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
633 This->multistate_funcs[i] = NULL;
636 /* TODO: Clean up all the surfaces and textures! */
637 /* NOTE: You must release the parent if the object was created via a callback
638 ** ***************************/
640 if (!list_empty(&This->resources))
642 IWineD3DResourceImpl *resource;
643 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
645 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
647 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
648 FIXME("Leftover resource %p with type %s (%#x).\n",
649 resource, debug_d3dresourcetype(type), type);
653 if(This->contexts) ERR("Context array not freed!\n");
654 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
655 This->haveHardwareCursor = FALSE;
657 IWineD3D_Release(This->wined3d);
658 This->wined3d = NULL;
659 HeapFree(GetProcessHeap(), 0, This);
660 TRACE("Freed device %p\n", This);
661 This = NULL;
663 return refCount;
666 /**********************************************************
667 * IWineD3DDevice implementation follows
668 **********************************************************/
669 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
671 *pParent = This->parent;
672 IUnknown_AddRef(This->parent);
673 return WINED3D_OK;
676 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
677 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 struct wined3d_buffer *object;
681 HRESULT hr;
683 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
685 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
686 if (!object)
688 ERR("Failed to allocate memory\n");
689 return E_OUTOFMEMORY;
692 FIXME("Ignoring access flags (pool)\n");
694 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
695 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
696 if (FAILED(hr))
698 WARN("Failed to initialize buffer, hr %#x.\n", hr);
699 HeapFree(GetProcessHeap(), 0, object);
700 return hr;
702 object->desc = *desc;
704 TRACE("Created buffer %p.\n", object);
706 *buffer = (IWineD3DBuffer *)object;
708 return WINED3D_OK;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
712 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
713 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
716 struct wined3d_buffer *object;
717 HRESULT hr;
719 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
720 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
722 if (Pool == WINED3DPOOL_SCRATCH)
724 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
725 * anyway, SCRATCH vertex buffers aren't usable anywhere
727 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
728 *ppVertexBuffer = NULL;
729 return WINED3DERR_INVALIDCALL;
732 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
733 if (!object)
735 ERR("Out of memory\n");
736 *ppVertexBuffer = NULL;
737 return WINED3DERR_OUTOFVIDEOMEMORY;
740 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
741 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
742 if (FAILED(hr))
744 WARN("Failed to initialize buffer, hr %#x.\n", hr);
745 HeapFree(GetProcessHeap(), 0, object);
746 return hr;
749 TRACE("Created buffer %p.\n", object);
750 *ppVertexBuffer = (IWineD3DBuffer *)object;
752 return WINED3D_OK;
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
756 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
757 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 struct wined3d_buffer *object;
761 HRESULT hr;
763 TRACE("(%p) Creating index buffer\n", This);
765 /* Allocate the storage for the device */
766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
767 if (!object)
769 ERR("Out of memory\n");
770 *ppIndexBuffer = NULL;
771 return WINED3DERR_OUTOFVIDEOMEMORY;
774 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
775 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
776 parent, parent_ops);
777 if (FAILED(hr))
779 WARN("Failed to initialize buffer, hr %#x\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
781 return hr;
784 TRACE("Created buffer %p.\n", object);
786 *ppIndexBuffer = (IWineD3DBuffer *) object;
788 return WINED3D_OK;
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
792 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DStateBlockImpl *object;
796 HRESULT hr;
798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
799 if(!object)
801 ERR("Failed to allocate stateblock memory.\n");
802 return E_OUTOFMEMORY;
805 hr = stateblock_init(object, This, type);
806 if (FAILED(hr))
808 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
809 HeapFree(GetProcessHeap(), 0, object);
810 return hr;
813 TRACE("Created stateblock %p.\n", object);
814 *stateblock = (IWineD3DStateBlock *)object;
816 return WINED3D_OK;
819 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
820 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
821 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
822 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
825 IWineD3DSurfaceImpl *object;
826 HRESULT hr;
828 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
829 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
830 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
831 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
832 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
834 if (Impl == SURFACE_OPENGL && !This->adapter)
836 ERR("OpenGL surfaces are not available without OpenGL.\n");
837 return WINED3DERR_NOTAVAILABLE;
840 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
841 if (!object)
843 ERR("Failed to allocate surface memory.\n");
844 return WINED3DERR_OUTOFVIDEOMEMORY;
847 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
848 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
849 if (FAILED(hr))
851 WARN("Failed to initialize surface, returning %#x.\n", hr);
852 HeapFree(GetProcessHeap(), 0, object);
853 return hr;
856 TRACE("(%p) : Created surface %p\n", This, object);
858 *ppSurface = (IWineD3DSurface *)object;
860 return hr;
863 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
864 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
866 struct wined3d_rendertarget_view *object;
868 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
869 iface, resource, parent, rendertarget_view);
871 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
872 if (!object)
874 ERR("Failed to allocate memory\n");
875 return E_OUTOFMEMORY;
878 wined3d_rendertarget_view_init(object, resource, parent);
880 TRACE("Created render target view %p.\n", object);
881 *rendertarget_view = (IWineD3DRendertargetView *)object;
883 return WINED3D_OK;
886 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
887 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
888 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
891 IWineD3DTextureImpl *object;
892 HRESULT hr;
894 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
895 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
896 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Out of memory\n");
902 *ppTexture = NULL;
903 return WINED3DERR_OUTOFVIDEOMEMORY;
906 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
907 if (FAILED(hr))
909 WARN("Failed to initialize texture, returning %#x\n", hr);
910 HeapFree(GetProcessHeap(), 0, object);
911 *ppTexture = NULL;
912 return hr;
915 *ppTexture = (IWineD3DTexture *)object;
917 TRACE("(%p) : Created texture %p\n", This, object);
919 return WINED3D_OK;
922 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
923 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
924 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DVolumeTextureImpl *object;
928 HRESULT hr;
930 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
931 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
933 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
934 if (!object)
936 ERR("Out of memory\n");
937 *ppVolumeTexture = NULL;
938 return WINED3DERR_OUTOFVIDEOMEMORY;
941 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
942 if (FAILED(hr))
944 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
945 HeapFree(GetProcessHeap(), 0, object);
946 *ppVolumeTexture = NULL;
947 return hr;
950 TRACE("(%p) : Created volume texture %p.\n", This, object);
951 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
953 return WINED3D_OK;
956 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
957 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
958 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
961 IWineD3DVolumeImpl *object;
962 HRESULT hr;
964 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
965 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
967 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
968 if (!object)
970 ERR("Out of memory\n");
971 *ppVolume = NULL;
972 return WINED3DERR_OUTOFVIDEOMEMORY;
975 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
976 if (FAILED(hr))
978 WARN("Failed to initialize volume, returning %#x.\n", hr);
979 HeapFree(GetProcessHeap(), 0, object);
980 return hr;
983 TRACE("(%p) : Created volume %p.\n", This, object);
984 *ppVolume = (IWineD3DVolume *)object;
986 return WINED3D_OK;
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
990 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
991 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
994 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
995 HRESULT hr;
997 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
998 if (!object)
1000 ERR("Out of memory\n");
1001 *ppCubeTexture = NULL;
1002 return WINED3DERR_OUTOFVIDEOMEMORY;
1005 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1006 if (FAILED(hr))
1008 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1009 HeapFree(GetProcessHeap(), 0, object);
1010 *ppCubeTexture = NULL;
1011 return hr;
1014 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1015 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1017 return WINED3D_OK;
1020 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1021 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1024 IWineD3DQueryImpl *object;
1025 HRESULT hr;
1027 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1029 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1030 if (!object)
1032 ERR("Failed to allocate query memory.\n");
1033 return E_OUTOFMEMORY;
1036 hr = query_init(object, This, type, parent);
1037 if (FAILED(hr))
1039 WARN("Failed to initialize query, hr %#x.\n", hr);
1040 HeapFree(GetProcessHeap(), 0, object);
1041 return hr;
1044 TRACE("Created query %p.\n", object);
1045 *query = (IWineD3DQuery *)object;
1047 return WINED3D_OK;
1050 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1051 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1052 IUnknown *parent, WINED3DSURFTYPE surface_type)
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DSwapChainImpl *object;
1056 HRESULT hr;
1058 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1059 iface, present_parameters, swapchain, parent, surface_type);
1061 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1062 if (!object)
1064 ERR("Failed to allocate swapchain memory.\n");
1065 return E_OUTOFMEMORY;
1068 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1069 if (FAILED(hr))
1071 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1072 HeapFree(GetProcessHeap(), 0, object);
1073 return hr;
1076 TRACE("Created swapchain %p.\n", object);
1077 *swapchain = (IWineD3DSwapChain *)object;
1079 return WINED3D_OK;
1082 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1083 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1085 TRACE("(%p)\n", This);
1087 return This->NumberOfSwapChains;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1094 if(iSwapChain < This->NumberOfSwapChains) {
1095 *pSwapChain = This->swapchains[iSwapChain];
1096 IWineD3DSwapChain_AddRef(*pSwapChain);
1097 TRACE("(%p) returning %p\n", This, *pSwapChain);
1098 return WINED3D_OK;
1099 } else {
1100 TRACE("Swapchain out of range\n");
1101 *pSwapChain = NULL;
1102 return WINED3DERR_INVALIDCALL;
1106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1107 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1108 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1111 IWineD3DVertexDeclarationImpl *object = NULL;
1112 HRESULT hr;
1114 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1115 iface, declaration, parent, elements, element_count);
1117 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1118 if(!object)
1120 ERR("Failed to allocate vertex declaration memory.\n");
1121 return E_OUTOFMEMORY;
1124 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1125 if (FAILED(hr))
1127 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1129 return hr;
1132 TRACE("Created vertex declaration %p.\n", object);
1133 *declaration = (IWineD3DVertexDeclaration *)object;
1135 return WINED3D_OK;
1138 struct wined3d_fvf_convert_state
1140 const struct wined3d_gl_info *gl_info;
1141 WINED3DVERTEXELEMENT *elements;
1142 UINT offset;
1143 UINT idx;
1146 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1147 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1149 WINED3DVERTEXELEMENT *elements = state->elements;
1150 const struct wined3d_format_desc *format_desc;
1151 UINT offset = state->offset;
1152 UINT idx = state->idx;
1154 elements[idx].format = format;
1155 elements[idx].input_slot = 0;
1156 elements[idx].offset = offset;
1157 elements[idx].output_slot = 0;
1158 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1159 elements[idx].usage = usage;
1160 elements[idx].usage_idx = usage_idx;
1162 format_desc = getFormatDescEntry(format, state->gl_info);
1163 state->offset += format_desc->component_count * format_desc->component_size;
1164 ++state->idx;
1167 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1168 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1170 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1171 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1172 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1173 BOOL has_blend_idx = has_blend &&
1174 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1175 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1176 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1177 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1178 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1179 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1180 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1182 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1183 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1184 struct wined3d_fvf_convert_state state;
1185 unsigned int size;
1186 unsigned int idx;
1187 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1188 if (has_blend_idx) num_blends--;
1190 /* Compute declaration size */
1191 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1192 has_psize + has_diffuse + has_specular + num_textures;
1194 state.gl_info = gl_info;
1195 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1196 if (!state.elements) return ~0U;
1197 state.offset = 0;
1198 state.idx = 0;
1200 if (has_pos)
1202 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1203 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1204 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1205 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1206 else
1207 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1210 if (has_blend && (num_blends > 0))
1212 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1213 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1214 else
1216 switch (num_blends)
1218 case 1:
1219 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1220 break;
1221 case 2:
1222 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1223 break;
1224 case 3:
1225 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1226 break;
1227 case 4:
1228 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1229 break;
1230 default:
1231 ERR("Unexpected amount of blend values: %u\n", num_blends);
1236 if (has_blend_idx)
1238 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1239 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1240 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1241 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1242 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1243 else
1244 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1247 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1248 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1249 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1250 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1252 for (idx = 0; idx < num_textures; ++idx)
1254 switch ((texcoords >> (idx * 2)) & 0x03)
1256 case WINED3DFVF_TEXTUREFORMAT1:
1257 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1258 break;
1259 case WINED3DFVF_TEXTUREFORMAT2:
1260 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1261 break;
1262 case WINED3DFVF_TEXTUREFORMAT3:
1263 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1264 break;
1265 case WINED3DFVF_TEXTUREFORMAT4:
1266 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1267 break;
1271 *ppVertexElements = state.elements;
1272 return size;
1275 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1276 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1277 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1280 WINED3DVERTEXELEMENT *elements;
1281 unsigned int size;
1282 DWORD hr;
1284 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1286 size = ConvertFvfToDeclaration(This, fvf, &elements);
1287 if (size == ~0U) return E_OUTOFMEMORY;
1289 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1290 HeapFree(GetProcessHeap(), 0, elements);
1291 return hr;
1294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1295 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1296 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1297 const struct wined3d_parent_ops *parent_ops)
1299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1300 IWineD3DVertexShaderImpl *object;
1301 HRESULT hr;
1303 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1304 if (!object)
1306 ERR("Failed to allocate shader memory.\n");
1307 return E_OUTOFMEMORY;
1310 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1311 if (FAILED(hr))
1313 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1314 HeapFree(GetProcessHeap(), 0, object);
1315 return hr;
1318 TRACE("Created vertex shader %p.\n", object);
1319 *ppVertexShader = (IWineD3DVertexShader *)object;
1321 return WINED3D_OK;
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1325 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1326 IWineD3DGeometryShader **shader, IUnknown *parent,
1327 const struct wined3d_parent_ops *parent_ops)
1329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1330 struct wined3d_geometryshader *object;
1331 HRESULT hr;
1333 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1334 if (!object)
1336 ERR("Failed to allocate shader memory.\n");
1337 return E_OUTOFMEMORY;
1340 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1341 if (FAILED(hr))
1343 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1344 HeapFree(GetProcessHeap(), 0, object);
1345 return hr;
1348 TRACE("Created geometry shader %p.\n", object);
1349 *shader = (IWineD3DGeometryShader *)object;
1351 return WINED3D_OK;
1354 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1355 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1356 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1357 const struct wined3d_parent_ops *parent_ops)
1359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1360 IWineD3DPixelShaderImpl *object;
1361 HRESULT hr;
1363 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1364 if (!object)
1366 ERR("Failed to allocate shader memory.\n");
1367 return E_OUTOFMEMORY;
1370 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1371 if (FAILED(hr))
1373 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1374 HeapFree(GetProcessHeap(), 0, object);
1375 return hr;
1378 TRACE("Created pixel shader %p.\n", object);
1379 *ppPixelShader = (IWineD3DPixelShader *)object;
1381 return WINED3D_OK;
1384 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1385 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1388 IWineD3DPaletteImpl *object;
1389 HRESULT hr;
1391 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1392 iface, Flags, PalEnt, Palette, Parent);
1394 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1395 if (!object)
1397 ERR("Failed to allocate palette memory.\n");
1398 return E_OUTOFMEMORY;
1401 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1402 if (FAILED(hr))
1404 WARN("Failed to initialize palette, hr %#x.\n", hr);
1405 HeapFree(GetProcessHeap(), 0, object);
1406 return hr;
1409 TRACE("Created palette %p.\n", object);
1410 *Palette = (IWineD3DPalette *)object;
1412 return WINED3D_OK;
1415 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1416 HBITMAP hbm;
1417 BITMAP bm;
1418 HRESULT hr;
1419 HDC dcb = NULL, dcs = NULL;
1420 WINEDDCOLORKEY colorkey;
1422 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1423 if(hbm)
1425 GetObjectA(hbm, sizeof(BITMAP), &bm);
1426 dcb = CreateCompatibleDC(NULL);
1427 if(!dcb) goto out;
1428 SelectObject(dcb, hbm);
1430 else
1432 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1433 * couldn't be loaded
1435 memset(&bm, 0, sizeof(bm));
1436 bm.bmWidth = 32;
1437 bm.bmHeight = 32;
1440 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1441 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1442 NULL, &wined3d_null_parent_ops);
1443 if(FAILED(hr)) {
1444 ERR("Wine logo requested, but failed to create surface\n");
1445 goto out;
1448 if(dcb) {
1449 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1450 if(FAILED(hr)) goto out;
1451 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1452 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1454 colorkey.dwColorSpaceLowValue = 0;
1455 colorkey.dwColorSpaceHighValue = 0;
1456 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1457 } else {
1458 /* Fill the surface with a white color to show that wined3d is there */
1459 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1462 out:
1463 if (dcb) DeleteDC(dcb);
1464 if (hbm) DeleteObject(hbm);
1467 /* Context activation is done by the caller. */
1468 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1470 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1471 unsigned int i;
1472 /* Under DirectX you can have texture stage operations even if no texture is
1473 bound, whereas opengl will only do texture operations when a valid texture is
1474 bound. We emulate this by creating dummy textures and binding them to each
1475 texture stage, but disable all stages by default. Hence if a stage is enabled
1476 then the default texture will kick in until replaced by a SetTexture call */
1477 ENTER_GL();
1479 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1481 /* The dummy texture does not have client storage backing */
1482 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1483 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1486 for (i = 0; i < gl_info->limits.textures; ++i)
1488 GLubyte white = 255;
1490 /* Make appropriate texture active */
1491 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1492 checkGLcall("glActiveTextureARB");
1494 /* Generate an opengl texture name */
1495 glGenTextures(1, &This->dummyTextureName[i]);
1496 checkGLcall("glGenTextures");
1497 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1499 /* Generate a dummy 2d texture (not using 1d because they cause many
1500 * DRI drivers fall back to sw) */
1501 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1502 checkGLcall("glBindTexture");
1504 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1505 checkGLcall("glTexImage2D");
1508 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1510 /* Reenable because if supported it is enabled by default */
1511 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1512 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1515 LEAVE_GL();
1518 /* Context activation is done by the caller. */
1519 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1521 ENTER_GL();
1522 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1523 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1524 LEAVE_GL();
1526 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1529 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1531 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1533 if (!wined3d_register_window(window, device))
1535 ERR("Failed to register window %p.\n", window);
1536 return E_FAIL;
1539 device->focus_window = window;
1540 SetForegroundWindow(window);
1542 return WINED3D_OK;
1545 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1547 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1549 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1550 device->focus_window = NULL;
1553 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1554 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1557 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1558 IWineD3DSwapChainImpl *swapchain = NULL;
1559 struct wined3d_context *context;
1560 HRESULT hr;
1561 DWORD state;
1562 unsigned int i;
1564 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1566 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1567 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1569 TRACE("(%p) : Creating stateblock\n", This);
1570 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1571 hr = IWineD3DDevice_CreateStateBlock(iface,
1572 WINED3DSBT_INIT,
1573 (IWineD3DStateBlock **)&This->stateBlock,
1574 NULL);
1575 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1576 WARN("Failed to create stateblock\n");
1577 goto err_out;
1579 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1580 This->updateStateBlock = This->stateBlock;
1581 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1583 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1584 sizeof(*This->render_targets) * gl_info->limits.buffers);
1585 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1586 sizeof(GLenum) * gl_info->limits.buffers);
1588 This->NumberOfPalettes = 1;
1589 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1590 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1591 ERR("Out of memory!\n");
1592 hr = E_OUTOFMEMORY;
1593 goto err_out;
1595 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1596 if(!This->palettes[0]) {
1597 ERR("Out of memory!\n");
1598 hr = E_OUTOFMEMORY;
1599 goto err_out;
1601 for (i = 0; i < 256; ++i) {
1602 This->palettes[0][i].peRed = 0xFF;
1603 This->palettes[0][i].peGreen = 0xFF;
1604 This->palettes[0][i].peBlue = 0xFF;
1605 This->palettes[0][i].peFlags = 0xFF;
1607 This->currentPalette = 0;
1609 /* Initialize the texture unit mapping to a 1:1 mapping */
1610 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1612 if (state < gl_info->limits.fragment_samplers)
1614 This->texUnitMap[state] = state;
1615 This->rev_tex_unit_map[state] = state;
1616 } else {
1617 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1618 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1622 /* Setup the implicit swapchain. This also initializes a context. */
1623 TRACE("Creating implicit swapchain\n");
1624 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1625 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1626 if (FAILED(hr))
1628 WARN("Failed to create implicit swapchain\n");
1629 goto err_out;
1632 This->NumberOfSwapChains = 1;
1633 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1634 if(!This->swapchains) {
1635 ERR("Out of memory!\n");
1636 goto err_out;
1638 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1640 if (swapchain->back_buffers && swapchain->back_buffers[0])
1642 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1643 This->render_targets[0] = swapchain->back_buffers[0];
1645 else
1647 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1648 This->render_targets[0] = swapchain->front_buffer;
1650 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1652 /* Depth Stencil support */
1653 This->depth_stencil = This->auto_depth_stencil;
1654 if (This->depth_stencil)
1655 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1657 hr = This->shader_backend->shader_alloc_private(iface);
1658 if(FAILED(hr)) {
1659 TRACE("Shader private data couldn't be allocated\n");
1660 goto err_out;
1662 hr = This->frag_pipe->alloc_private(iface);
1663 if(FAILED(hr)) {
1664 TRACE("Fragment pipeline private data couldn't be allocated\n");
1665 goto err_out;
1667 hr = This->blitter->alloc_private(iface);
1668 if(FAILED(hr)) {
1669 TRACE("Blitter private data couldn't be allocated\n");
1670 goto err_out;
1673 /* Set up some starting GL setup */
1675 /* Setup all the devices defaults */
1676 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1678 context = context_acquire(This, swapchain->front_buffer);
1680 create_dummy_textures(This);
1682 ENTER_GL();
1684 /* Initialize the current view state */
1685 This->view_ident = 1;
1686 This->contexts[0]->last_was_rhw = 0;
1687 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1688 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1690 switch(wined3d_settings.offscreen_rendering_mode) {
1691 case ORM_FBO:
1692 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1693 break;
1695 case ORM_BACKBUFFER:
1697 if (context_get_current()->aux_buffers > 0)
1699 TRACE("Using auxilliary buffer for offscreen rendering\n");
1700 This->offscreenBuffer = GL_AUX0;
1701 } else {
1702 TRACE("Using back buffer for offscreen rendering\n");
1703 This->offscreenBuffer = GL_BACK;
1708 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1709 LEAVE_GL();
1711 context_release(context);
1713 /* Clear the screen */
1714 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1715 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1716 0x00, 1.0f, 0);
1718 This->d3d_initialized = TRUE;
1720 if(wined3d_settings.logo) {
1721 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1723 This->highest_dirty_ps_const = 0;
1724 This->highest_dirty_vs_const = 0;
1725 return WINED3D_OK;
1727 err_out:
1728 HeapFree(GetProcessHeap(), 0, This->render_targets);
1729 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1730 HeapFree(GetProcessHeap(), 0, This->swapchains);
1731 This->NumberOfSwapChains = 0;
1732 if(This->palettes) {
1733 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1734 HeapFree(GetProcessHeap(), 0, This->palettes);
1736 This->NumberOfPalettes = 0;
1737 if(swapchain) {
1738 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1740 if(This->stateBlock) {
1741 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1742 This->stateBlock = NULL;
1744 if (This->blit_priv) {
1745 This->blitter->free_private(iface);
1747 if (This->fragment_priv) {
1748 This->frag_pipe->free_private(iface);
1750 if (This->shader_priv) {
1751 This->shader_backend->shader_free_private(iface);
1753 return hr;
1756 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1757 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1760 IWineD3DSwapChainImpl *swapchain = NULL;
1761 HRESULT hr;
1763 /* Setup the implicit swapchain */
1764 TRACE("Creating implicit swapchain\n");
1765 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1766 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1767 if (FAILED(hr))
1769 WARN("Failed to create implicit swapchain\n");
1770 goto err_out;
1773 This->NumberOfSwapChains = 1;
1774 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1775 if(!This->swapchains) {
1776 ERR("Out of memory!\n");
1777 goto err_out;
1779 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1780 return WINED3D_OK;
1782 err_out:
1783 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1784 return hr;
1787 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1789 IWineD3DResource_UnLoad(resource);
1790 IWineD3DResource_Release(resource);
1791 return WINED3D_OK;
1794 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1795 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1798 const struct wined3d_gl_info *gl_info;
1799 struct wined3d_context *context;
1800 int sampler;
1801 UINT i;
1802 TRACE("(%p)\n", This);
1804 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1806 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1807 * it was created. Thus make sure a context is active for the glDelete* calls
1809 context = context_acquire(This, NULL);
1810 gl_info = context->gl_info;
1812 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1814 /* Unload resources */
1815 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1817 TRACE("Deleting high order patches\n");
1818 for(i = 0; i < PATCHMAP_SIZE; i++) {
1819 struct list *e1, *e2;
1820 struct WineD3DRectPatch *patch;
1821 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1822 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1823 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1827 /* Delete the mouse cursor texture */
1828 if(This->cursorTexture) {
1829 ENTER_GL();
1830 glDeleteTextures(1, &This->cursorTexture);
1831 LEAVE_GL();
1832 This->cursorTexture = 0;
1835 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1836 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1838 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1839 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1842 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1843 * private data, it might contain opengl pointers
1845 if(This->depth_blt_texture) {
1846 ENTER_GL();
1847 glDeleteTextures(1, &This->depth_blt_texture);
1848 LEAVE_GL();
1849 This->depth_blt_texture = 0;
1851 if (This->depth_blt_rb) {
1852 ENTER_GL();
1853 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1854 LEAVE_GL();
1855 This->depth_blt_rb = 0;
1856 This->depth_blt_rb_w = 0;
1857 This->depth_blt_rb_h = 0;
1860 /* Release the update stateblock */
1861 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1862 if(This->updateStateBlock != This->stateBlock)
1863 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1865 This->updateStateBlock = NULL;
1867 { /* because were not doing proper internal refcounts releasing the primary state block
1868 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1869 to set this->stateBlock = NULL; first */
1870 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1871 This->stateBlock = NULL;
1873 /* Release the stateblock */
1874 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1875 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1879 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1880 This->blitter->free_private(iface);
1881 This->frag_pipe->free_private(iface);
1882 This->shader_backend->shader_free_private(iface);
1884 /* Release the buffers (with sanity checks)*/
1885 if (This->onscreen_depth_stencil)
1887 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1888 This->onscreen_depth_stencil = NULL;
1891 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1892 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1894 if (This->auto_depth_stencil != This->depth_stencil)
1895 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1897 This->depth_stencil = NULL;
1899 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1900 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1902 TRACE("Setting rendertarget to NULL\n");
1903 This->render_targets[0] = NULL;
1905 if (This->auto_depth_stencil)
1907 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1909 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1911 This->auto_depth_stencil = NULL;
1914 context_release(context);
1916 for(i=0; i < This->NumberOfSwapChains; i++) {
1917 TRACE("Releasing the implicit swapchain %d\n", i);
1918 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1919 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1923 HeapFree(GetProcessHeap(), 0, This->swapchains);
1924 This->swapchains = NULL;
1925 This->NumberOfSwapChains = 0;
1927 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1928 HeapFree(GetProcessHeap(), 0, This->palettes);
1929 This->palettes = NULL;
1930 This->NumberOfPalettes = 0;
1932 HeapFree(GetProcessHeap(), 0, This->render_targets);
1933 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1934 This->render_targets = NULL;
1935 This->draw_buffers = NULL;
1937 This->d3d_initialized = FALSE;
1939 return WINED3D_OK;
1942 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1944 unsigned int i;
1946 for(i=0; i < This->NumberOfSwapChains; i++) {
1947 TRACE("Releasing the implicit swapchain %d\n", i);
1948 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1949 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1953 HeapFree(GetProcessHeap(), 0, This->swapchains);
1954 This->swapchains = NULL;
1955 This->NumberOfSwapChains = 0;
1956 return WINED3D_OK;
1959 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1960 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1961 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1963 * There is no way to deactivate thread safety once it is enabled.
1965 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1968 /*For now just store the flag(needed in case of ddraw) */
1969 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1972 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1973 const WINED3DDISPLAYMODE* pMode) {
1974 DEVMODEW devmode;
1975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1976 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1977 LONG ret;
1978 RECT clip_rc;
1980 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1982 /* Resize the screen even without a window:
1983 * The app could have unset it with SetCooperativeLevel, but not called
1984 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1985 * but we don't have any hwnd
1988 memset(&devmode, 0, sizeof(devmode));
1989 devmode.dmSize = sizeof(devmode);
1990 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1991 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1992 devmode.dmPelsWidth = pMode->Width;
1993 devmode.dmPelsHeight = pMode->Height;
1995 devmode.dmDisplayFrequency = pMode->RefreshRate;
1996 if (pMode->RefreshRate != 0) {
1997 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2000 /* Only change the mode if necessary */
2001 if( (This->ddraw_width == pMode->Width) &&
2002 (This->ddraw_height == pMode->Height) &&
2003 (This->ddraw_format == pMode->Format) &&
2004 (pMode->RefreshRate == 0) ) {
2005 return WINED3D_OK;
2008 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2009 if (ret != DISP_CHANGE_SUCCESSFUL) {
2010 if(devmode.dmDisplayFrequency != 0) {
2011 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2012 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2013 devmode.dmDisplayFrequency = 0;
2014 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2016 if(ret != DISP_CHANGE_SUCCESSFUL) {
2017 return WINED3DERR_NOTAVAILABLE;
2021 /* Store the new values */
2022 This->ddraw_width = pMode->Width;
2023 This->ddraw_height = pMode->Height;
2024 This->ddraw_format = pMode->Format;
2026 /* And finally clip mouse to our screen */
2027 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2028 ClipCursor(&clip_rc);
2030 return WINED3D_OK;
2033 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2035 *ppD3D = This->wined3d;
2036 TRACE("Returning %p.\n", *ppD3D);
2037 IWineD3D_AddRef(*ppD3D);
2038 return WINED3D_OK;
2041 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2044 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2045 (This->adapter->TextureRam/(1024*1024)),
2046 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2047 /* return simulated texture memory left */
2048 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2051 /*****
2052 * Get / Set Stream Source
2053 *****/
2054 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2055 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2058 IWineD3DBuffer *oldSrc;
2060 if (StreamNumber >= MAX_STREAMS) {
2061 WARN("Stream out of range %d\n", StreamNumber);
2062 return WINED3DERR_INVALIDCALL;
2063 } else if(OffsetInBytes & 0x3) {
2064 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2065 return WINED3DERR_INVALIDCALL;
2068 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2069 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2071 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2073 if(oldSrc == pStreamData &&
2074 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2075 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2076 TRACE("Application is setting the old values over, nothing to do\n");
2077 return WINED3D_OK;
2080 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2081 if (pStreamData) {
2082 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2083 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2086 /* Handle recording of state blocks */
2087 if (This->isRecordingState) {
2088 TRACE("Recording... not performing anything\n");
2089 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2090 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2091 return WINED3D_OK;
2094 if (pStreamData != NULL) {
2095 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2096 IWineD3DBuffer_AddRef(pStreamData);
2098 if (oldSrc != NULL) {
2099 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2100 IWineD3DBuffer_Release(oldSrc);
2103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2105 return WINED3D_OK;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2109 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2113 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2114 This->stateBlock->streamSource[StreamNumber],
2115 This->stateBlock->streamOffset[StreamNumber],
2116 This->stateBlock->streamStride[StreamNumber]);
2118 if (StreamNumber >= MAX_STREAMS) {
2119 WARN("Stream out of range %d\n", StreamNumber);
2120 return WINED3DERR_INVALIDCALL;
2122 *pStream = This->stateBlock->streamSource[StreamNumber];
2123 *pStride = This->stateBlock->streamStride[StreamNumber];
2124 if (pOffset) {
2125 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2128 if (*pStream != NULL) {
2129 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2131 return WINED3D_OK;
2134 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2136 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2137 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2139 /* Verify input at least in d3d9 this is invalid*/
2140 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2141 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2142 return WINED3DERR_INVALIDCALL;
2144 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2145 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2146 return WINED3DERR_INVALIDCALL;
2148 if( Divider == 0 ){
2149 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2150 return WINED3DERR_INVALIDCALL;
2153 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2154 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2156 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2157 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2159 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2160 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2164 return WINED3D_OK;
2167 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2170 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2171 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2173 TRACE("(%p) : returning %d\n", This, *Divider);
2175 return WINED3D_OK;
2178 /*****
2179 * Get / Set & Multiply Transform
2180 *****/
2181 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2184 /* Most of this routine, comments included copied from ddraw tree initially: */
2185 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2187 /* Handle recording of state blocks */
2188 if (This->isRecordingState) {
2189 TRACE("Recording... not performing anything\n");
2190 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2191 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2192 return WINED3D_OK;
2196 * If the new matrix is the same as the current one,
2197 * we cut off any further processing. this seems to be a reasonable
2198 * optimization because as was noticed, some apps (warcraft3 for example)
2199 * tend towards setting the same matrix repeatedly for some reason.
2201 * From here on we assume that the new matrix is different, wherever it matters.
2203 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2204 TRACE("The app is setting the same matrix over again\n");
2205 return WINED3D_OK;
2206 } else {
2207 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2211 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2212 where ViewMat = Camera space, WorldMat = world space.
2214 In OpenGL, camera and world space is combined into GL_MODELVIEW
2215 matrix. The Projection matrix stay projection matrix.
2218 /* Capture the times we can just ignore the change for now */
2219 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2220 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2221 /* Handled by the state manager */
2224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2225 return WINED3D_OK;
2228 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2230 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2231 *pMatrix = This->stateBlock->transforms[State];
2232 return WINED3D_OK;
2235 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2236 const WINED3DMATRIX *mat = NULL;
2237 WINED3DMATRIX temp;
2239 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2240 * below means it will be recorded in a state block change, but it
2241 * works regardless where it is recorded.
2242 * If this is found to be wrong, change to StateBlock.
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2247 if (State <= HIGHEST_TRANSFORMSTATE)
2249 mat = &This->updateStateBlock->transforms[State];
2250 } else {
2251 FIXME("Unhandled transform state!!\n");
2254 multiply_matrix(&temp, mat, pMatrix);
2256 /* Apply change via set transform - will reapply to eg. lights this way */
2257 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2260 /*****
2261 * Get / Set Light
2262 *****/
2263 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2264 you can reference any indexes you want as long as that number max are enabled at any
2265 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2266 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2267 but when recording, just build a chain pretty much of commands to be replayed. */
2269 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2270 float rho;
2271 struct wined3d_light_info *object = NULL;
2272 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2273 struct list *e;
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2276 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2278 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2279 * the gl driver.
2281 if(!pLight) {
2282 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2283 return WINED3DERR_INVALIDCALL;
2286 switch(pLight->Type) {
2287 case WINED3DLIGHT_POINT:
2288 case WINED3DLIGHT_SPOT:
2289 case WINED3DLIGHT_PARALLELPOINT:
2290 case WINED3DLIGHT_GLSPOT:
2291 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2292 * most wanted
2294 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2296 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2297 return WINED3DERR_INVALIDCALL;
2299 break;
2301 case WINED3DLIGHT_DIRECTIONAL:
2302 /* Ignores attenuation */
2303 break;
2305 default:
2306 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2307 return WINED3DERR_INVALIDCALL;
2310 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2312 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2313 if(object->OriginalIndex == Index) break;
2314 object = NULL;
2317 if(!object) {
2318 TRACE("Adding new light\n");
2319 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2320 if(!object) {
2321 ERR("Out of memory error when allocating a light\n");
2322 return E_OUTOFMEMORY;
2324 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2325 object->glIndex = -1;
2326 object->OriginalIndex = Index;
2329 /* Initialize the object */
2330 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,
2331 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2332 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2333 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2334 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2335 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2336 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2338 /* Save away the information */
2339 object->OriginalParms = *pLight;
2341 switch (pLight->Type) {
2342 case WINED3DLIGHT_POINT:
2343 /* Position */
2344 object->lightPosn[0] = pLight->Position.x;
2345 object->lightPosn[1] = pLight->Position.y;
2346 object->lightPosn[2] = pLight->Position.z;
2347 object->lightPosn[3] = 1.0f;
2348 object->cutoff = 180.0f;
2349 /* FIXME: Range */
2350 break;
2352 case WINED3DLIGHT_DIRECTIONAL:
2353 /* Direction */
2354 object->lightPosn[0] = -pLight->Direction.x;
2355 object->lightPosn[1] = -pLight->Direction.y;
2356 object->lightPosn[2] = -pLight->Direction.z;
2357 object->lightPosn[3] = 0.0f;
2358 object->exponent = 0.0f;
2359 object->cutoff = 180.0f;
2360 break;
2362 case WINED3DLIGHT_SPOT:
2363 /* Position */
2364 object->lightPosn[0] = pLight->Position.x;
2365 object->lightPosn[1] = pLight->Position.y;
2366 object->lightPosn[2] = pLight->Position.z;
2367 object->lightPosn[3] = 1.0f;
2369 /* Direction */
2370 object->lightDirn[0] = pLight->Direction.x;
2371 object->lightDirn[1] = pLight->Direction.y;
2372 object->lightDirn[2] = pLight->Direction.z;
2373 object->lightDirn[3] = 1.0f;
2376 * opengl-ish and d3d-ish spot lights use too different models for the
2377 * light "intensity" as a function of the angle towards the main light direction,
2378 * so we only can approximate very roughly.
2379 * however spot lights are rather rarely used in games (if ever used at all).
2380 * furthermore if still used, probably nobody pays attention to such details.
2382 if (pLight->Falloff == 0) {
2383 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2384 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2385 * will always be 1.0 for both of them, and we don't have to care for the
2386 * rest of the rather complex calculation
2388 object->exponent = 0.0f;
2389 } else {
2390 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2391 if (rho < 0.0001f) rho = 0.0001f;
2392 object->exponent = -0.3f/logf(cosf(rho/2));
2394 if (object->exponent > 128.0f)
2396 object->exponent = 128.0f;
2398 object->cutoff = pLight->Phi*90/M_PI;
2400 /* FIXME: Range */
2401 break;
2403 default:
2404 FIXME("Unrecognized light type %d\n", pLight->Type);
2407 /* Update the live definitions if the light is currently assigned a glIndex */
2408 if (object->glIndex != -1 && !This->isRecordingState) {
2409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2411 return WINED3D_OK;
2414 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2416 struct wined3d_light_info *lightInfo = NULL;
2417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2418 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2419 struct list *e;
2420 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2422 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2424 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2425 if(lightInfo->OriginalIndex == Index) break;
2426 lightInfo = NULL;
2429 if (lightInfo == NULL) {
2430 TRACE("Light information requested but light not defined\n");
2431 return WINED3DERR_INVALIDCALL;
2434 *pLight = lightInfo->OriginalParms;
2435 return WINED3D_OK;
2438 /*****
2439 * Get / Set Light Enable
2440 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2441 *****/
2442 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2444 struct wined3d_light_info *lightInfo = NULL;
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2446 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2447 struct list *e;
2448 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2450 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2452 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2453 if(lightInfo->OriginalIndex == Index) break;
2454 lightInfo = NULL;
2456 TRACE("Found light: %p\n", lightInfo);
2458 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2459 if (lightInfo == NULL) {
2461 TRACE("Light enabled requested but light not defined, so defining one!\n");
2462 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2464 /* Search for it again! Should be fairly quick as near head of list */
2465 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2467 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2468 if(lightInfo->OriginalIndex == Index) break;
2469 lightInfo = NULL;
2471 if (lightInfo == NULL) {
2472 FIXME("Adding default lights has failed dismally\n");
2473 return WINED3DERR_INVALIDCALL;
2477 if(!Enable) {
2478 if(lightInfo->glIndex != -1) {
2479 if(!This->isRecordingState) {
2480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2483 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2484 lightInfo->glIndex = -1;
2485 } else {
2486 TRACE("Light already disabled, nothing to do\n");
2488 lightInfo->enabled = FALSE;
2489 } else {
2490 lightInfo->enabled = TRUE;
2491 if (lightInfo->glIndex != -1) {
2492 /* nop */
2493 TRACE("Nothing to do as light was enabled\n");
2494 } else {
2495 int i;
2496 /* Find a free gl light */
2497 for(i = 0; i < This->maxConcurrentLights; i++) {
2498 if(This->updateStateBlock->activeLights[i] == NULL) {
2499 This->updateStateBlock->activeLights[i] = lightInfo;
2500 lightInfo->glIndex = i;
2501 break;
2504 if(lightInfo->glIndex == -1) {
2505 /* Our tests show that Windows returns D3D_OK in this situation, even with
2506 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2507 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2508 * as well for those lights.
2510 * TODO: Test how this affects rendering
2512 WARN("Too many concurrently active lights\n");
2513 return WINED3D_OK;
2516 /* i == lightInfo->glIndex */
2517 if(!This->isRecordingState) {
2518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2523 return WINED3D_OK;
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2528 struct wined3d_light_info *lightInfo = NULL;
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 struct list *e;
2531 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2532 TRACE("(%p) : for idx(%d)\n", This, Index);
2534 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2536 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2537 if(lightInfo->OriginalIndex == Index) break;
2538 lightInfo = NULL;
2541 if (lightInfo == NULL) {
2542 TRACE("Light enabled state requested but light not defined\n");
2543 return WINED3DERR_INVALIDCALL;
2545 /* true is 128 according to SetLightEnable */
2546 *pEnable = lightInfo->enabled ? 128 : 0;
2547 return WINED3D_OK;
2550 /*****
2551 * Get / Set Clip Planes
2552 *****/
2553 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2555 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2557 /* Validate Index */
2558 if (Index >= This->adapter->gl_info.limits.clipplanes)
2560 TRACE("Application has requested clipplane this device doesn't support\n");
2561 return WINED3DERR_INVALIDCALL;
2564 This->updateStateBlock->changed.clipplane |= 1 << Index;
2566 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2567 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2568 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2569 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2570 TRACE("Application is setting old values over, nothing to do\n");
2571 return WINED3D_OK;
2574 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2575 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2576 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2577 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2579 /* Handle recording of state blocks */
2580 if (This->isRecordingState) {
2581 TRACE("Recording... not performing anything\n");
2582 return WINED3D_OK;
2585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2587 return WINED3D_OK;
2590 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2592 TRACE("(%p) : for idx %d\n", This, Index);
2594 /* Validate Index */
2595 if (Index >= This->adapter->gl_info.limits.clipplanes)
2597 TRACE("Application has requested clipplane this device doesn't support\n");
2598 return WINED3DERR_INVALIDCALL;
2601 pPlane[0] = This->stateBlock->clipplane[Index][0];
2602 pPlane[1] = This->stateBlock->clipplane[Index][1];
2603 pPlane[2] = This->stateBlock->clipplane[Index][2];
2604 pPlane[3] = This->stateBlock->clipplane[Index][3];
2605 return WINED3D_OK;
2608 /*****
2609 * Get / Set Clip Plane Status
2610 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2611 *****/
2612 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 FIXME("(%p) : stub\n", This);
2615 if (NULL == pClipStatus) {
2616 return WINED3DERR_INVALIDCALL;
2618 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2619 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 FIXME("(%p) : stub\n", This);
2626 if (NULL == pClipStatus) {
2627 return WINED3DERR_INVALIDCALL;
2629 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2630 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2631 return WINED3D_OK;
2634 /*****
2635 * Get / Set Material
2636 *****/
2637 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 This->updateStateBlock->changed.material = TRUE;
2641 This->updateStateBlock->material = *pMaterial;
2643 /* Handle recording of state blocks */
2644 if (This->isRecordingState) {
2645 TRACE("Recording... not performing anything\n");
2646 return WINED3D_OK;
2649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2650 return WINED3D_OK;
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 *pMaterial = This->updateStateBlock->material;
2656 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2657 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2658 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2659 pMaterial->Ambient.b, pMaterial->Ambient.a);
2660 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2661 pMaterial->Specular.b, pMaterial->Specular.a);
2662 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2663 pMaterial->Emissive.b, pMaterial->Emissive.a);
2664 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2666 return WINED3D_OK;
2669 /*****
2670 * Get / Set Indices
2671 *****/
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2673 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 IWineD3DBuffer *oldIdxs;
2678 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2679 oldIdxs = This->updateStateBlock->pIndexData;
2681 This->updateStateBlock->changed.indices = TRUE;
2682 This->updateStateBlock->pIndexData = pIndexData;
2683 This->updateStateBlock->IndexFmt = fmt;
2685 /* Handle recording of state blocks */
2686 if (This->isRecordingState) {
2687 TRACE("Recording... not performing anything\n");
2688 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2689 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2690 return WINED3D_OK;
2693 if(oldIdxs != pIndexData) {
2694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2695 if(pIndexData) {
2696 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2697 IWineD3DBuffer_AddRef(pIndexData);
2699 if(oldIdxs) {
2700 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2701 IWineD3DBuffer_Release(oldIdxs);
2705 return WINED3D_OK;
2708 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 *ppIndexData = This->stateBlock->pIndexData;
2714 /* up ref count on ppindexdata */
2715 if (*ppIndexData) {
2716 IWineD3DBuffer_AddRef(*ppIndexData);
2717 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2718 }else{
2719 TRACE("(%p) No index data set\n", This);
2721 TRACE("Returning %p\n", *ppIndexData);
2723 return WINED3D_OK;
2726 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2727 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2729 TRACE("(%p)->(%d)\n", This, BaseIndex);
2731 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2732 TRACE("Application is setting the old value over, nothing to do\n");
2733 return WINED3D_OK;
2736 This->updateStateBlock->baseVertexIndex = BaseIndex;
2738 if (This->isRecordingState) {
2739 TRACE("Recording... not performing anything\n");
2740 return WINED3D_OK;
2742 /* The base vertex index affects the stream sources */
2743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2744 return WINED3D_OK;
2747 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 TRACE("(%p) : base_index %p\n", This, base_index);
2751 *base_index = This->stateBlock->baseVertexIndex;
2753 TRACE("Returning %u\n", *base_index);
2755 return WINED3D_OK;
2758 /*****
2759 * Get / Set Viewports
2760 *****/
2761 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 TRACE("(%p)\n", This);
2765 This->updateStateBlock->changed.viewport = TRUE;
2766 This->updateStateBlock->viewport = *pViewport;
2768 /* Handle recording of state blocks */
2769 if (This->isRecordingState) {
2770 TRACE("Recording... not performing anything\n");
2771 return WINED3D_OK;
2774 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2775 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2778 return WINED3D_OK;
2782 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 TRACE("(%p)\n", This);
2785 *pViewport = This->stateBlock->viewport;
2786 return WINED3D_OK;
2789 /*****
2790 * Get / Set Render States
2791 * TODO: Verify against dx9 definitions
2792 *****/
2793 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 DWORD oldValue = This->stateBlock->renderState[State];
2798 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2800 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2801 This->updateStateBlock->renderState[State] = Value;
2803 /* Handle recording of state blocks */
2804 if (This->isRecordingState) {
2805 TRACE("Recording... not performing anything\n");
2806 return WINED3D_OK;
2809 /* Compared here and not before the assignment to allow proper stateblock recording */
2810 if(Value == oldValue) {
2811 TRACE("Application is setting the old value over, nothing to do\n");
2812 } else {
2813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2816 return WINED3D_OK;
2819 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2821 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2822 *pValue = This->stateBlock->renderState[State];
2823 return WINED3D_OK;
2826 /*****
2827 * Get / Set Sampler States
2828 * TODO: Verify against dx9 definitions
2829 *****/
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 DWORD oldValue;
2835 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2836 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2838 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2839 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2842 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2843 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2844 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2847 * SetSampler is designed to allow for more than the standard up to 8 textures
2848 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2849 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2851 * http://developer.nvidia.com/object/General_FAQ.html#t6
2853 * There are two new settings for GForce
2854 * the sampler one:
2855 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2856 * and the texture one:
2857 * GL_MAX_TEXTURE_COORDS_ARB.
2858 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2859 ******************/
2861 oldValue = This->stateBlock->samplerState[Sampler][Type];
2862 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2863 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2865 /* Handle recording of state blocks */
2866 if (This->isRecordingState) {
2867 TRACE("Recording... not performing anything\n");
2868 return WINED3D_OK;
2871 if(oldValue == Value) {
2872 TRACE("Application is setting the old value over, nothing to do\n");
2873 return WINED3D_OK;
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2878 return WINED3D_OK;
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2885 This, Sampler, debug_d3dsamplerstate(Type), Type);
2887 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2888 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2891 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2892 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2893 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2895 *Value = This->stateBlock->samplerState[Sampler][Type];
2896 TRACE("(%p) : Returning %#x\n", This, *Value);
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 This->updateStateBlock->changed.scissorRect = TRUE;
2905 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2906 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2907 return WINED3D_OK;
2909 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2911 if(This->isRecordingState) {
2912 TRACE("Recording... not performing anything\n");
2913 return WINED3D_OK;
2916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2918 return WINED3D_OK;
2921 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 *pRect = This->updateStateBlock->scissorRect;
2925 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2926 return WINED3D_OK;
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2931 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2933 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2935 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2936 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2938 This->updateStateBlock->vertexDecl = pDecl;
2939 This->updateStateBlock->changed.vertexDecl = TRUE;
2941 if (This->isRecordingState) {
2942 TRACE("Recording... not performing anything\n");
2943 return WINED3D_OK;
2944 } else if(pDecl == oldDecl) {
2945 /* Checked after the assignment to allow proper stateblock recording */
2946 TRACE("Application is setting the old declaration over, nothing to do\n");
2947 return WINED3D_OK;
2950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2951 return WINED3D_OK;
2954 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2959 *ppDecl = This->stateBlock->vertexDecl;
2960 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2961 return WINED3D_OK;
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2968 This->updateStateBlock->vertexShader = pShader;
2969 This->updateStateBlock->changed.vertexShader = TRUE;
2971 if (This->isRecordingState) {
2972 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2973 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2974 TRACE("Recording... not performing anything\n");
2975 return WINED3D_OK;
2976 } else if(oldShader == pShader) {
2977 /* Checked here to allow proper stateblock recording */
2978 TRACE("App is setting the old shader over, nothing to do\n");
2979 return WINED3D_OK;
2982 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2983 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2984 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2988 return WINED3D_OK;
2991 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2994 if (NULL == ppShader) {
2995 return WINED3DERR_INVALIDCALL;
2997 *ppShader = This->stateBlock->vertexShader;
2998 if( NULL != *ppShader)
2999 IWineD3DVertexShader_AddRef(*ppShader);
3001 TRACE("(%p) : returning %p\n", This, *ppShader);
3002 return WINED3D_OK;
3005 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3006 IWineD3DDevice *iface,
3007 UINT start,
3008 CONST BOOL *srcData,
3009 UINT count) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3014 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3015 iface, srcData, start, count);
3017 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3019 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3020 for (i = 0; i < cnt; i++)
3021 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3023 for (i = start; i < cnt + start; ++i) {
3024 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3027 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3029 return WINED3D_OK;
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3033 IWineD3DDevice *iface,
3034 UINT start,
3035 BOOL *dstData,
3036 UINT count) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 int cnt = min(count, MAX_CONST_B - start);
3041 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3042 iface, dstData, start, count);
3044 if (dstData == NULL || cnt < 0)
3045 return WINED3DERR_INVALIDCALL;
3047 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3048 return WINED3D_OK;
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3052 IWineD3DDevice *iface,
3053 UINT start,
3054 CONST int *srcData,
3055 UINT count) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3060 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3061 iface, srcData, start, count);
3063 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3065 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3066 for (i = 0; i < cnt; i++)
3067 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3068 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3070 for (i = start; i < cnt + start; ++i) {
3071 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3074 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3076 return WINED3D_OK;
3079 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3080 IWineD3DDevice *iface,
3081 UINT start,
3082 int *dstData,
3083 UINT count) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 int cnt = min(count, MAX_CONST_I - start);
3088 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3089 iface, dstData, start, count);
3091 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3092 return WINED3DERR_INVALIDCALL;
3094 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3099 IWineD3DDevice *iface,
3100 UINT start,
3101 CONST float *srcData,
3102 UINT count) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 UINT i;
3107 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3108 iface, srcData, start, count);
3110 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3111 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3112 return WINED3DERR_INVALIDCALL;
3114 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3115 if(TRACE_ON(d3d)) {
3116 for (i = 0; i < count; i++)
3117 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3118 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3121 if (!This->isRecordingState)
3123 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3127 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3128 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3130 return WINED3D_OK;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3134 IWineD3DDevice *iface,
3135 UINT start,
3136 float *dstData,
3137 UINT count) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 int cnt = min(count, This->d3d_vshader_constantF - start);
3142 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3143 iface, dstData, start, count);
3145 if (dstData == NULL || cnt < 0)
3146 return WINED3DERR_INVALIDCALL;
3148 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3149 return WINED3D_OK;
3152 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3153 DWORD i;
3154 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3160 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3162 DWORD i = This->rev_tex_unit_map[unit];
3163 DWORD j = This->texUnitMap[stage];
3165 This->texUnitMap[stage] = unit;
3166 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3168 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3171 This->rev_tex_unit_map[unit] = stage;
3172 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3174 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3178 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3179 int i;
3181 This->fixed_function_usage_map = 0;
3182 for (i = 0; i < MAX_TEXTURES; ++i) {
3183 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3184 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3185 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3186 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3187 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3188 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3189 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3190 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3192 if (color_op == WINED3DTOP_DISABLE) {
3193 /* Not used, and disable higher stages */
3194 break;
3197 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3198 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3199 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3200 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3201 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3202 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3203 This->fixed_function_usage_map |= (1 << i);
3206 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3207 This->fixed_function_usage_map |= (1 << (i + 1));
3212 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3214 unsigned int i, tex;
3215 WORD ffu_map;
3217 device_update_fixed_function_usage_map(This);
3218 ffu_map = This->fixed_function_usage_map;
3220 if (This->max_ffp_textures == gl_info->limits.texture_stages
3221 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3223 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3225 if (!(ffu_map & 1)) continue;
3227 if (This->texUnitMap[i] != i) {
3228 device_map_stage(This, i, i);
3229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3230 markTextureStagesDirty(This, i);
3233 return;
3236 /* Now work out the mapping */
3237 tex = 0;
3238 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3240 if (!(ffu_map & 1)) continue;
3242 if (This->texUnitMap[i] != tex) {
3243 device_map_stage(This, i, tex);
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3245 markTextureStagesDirty(This, i);
3248 ++tex;
3252 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3254 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3255 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3256 unsigned int i;
3258 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3259 if (sampler_type[i] && This->texUnitMap[i] != i)
3261 device_map_stage(This, i, i);
3262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3263 if (i < gl_info->limits.texture_stages)
3265 markTextureStagesDirty(This, i);
3271 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3272 const DWORD *vshader_sampler_tokens, DWORD unit)
3274 DWORD current_mapping = This->rev_tex_unit_map[unit];
3276 /* Not currently used */
3277 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3279 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3280 /* Used by a fragment sampler */
3282 if (!pshader_sampler_tokens) {
3283 /* No pixel shader, check fixed function */
3284 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3287 /* Pixel shader, check the shader's sampler map */
3288 return !pshader_sampler_tokens[current_mapping];
3291 /* Used by a vertex sampler */
3292 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3295 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3297 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3298 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3299 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3300 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3301 int i;
3303 if (ps) {
3304 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3306 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3307 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3308 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3311 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3312 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3313 if (vshader_sampler_type[i])
3315 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3317 /* Already mapped somewhere */
3318 continue;
3321 while (start >= 0) {
3322 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3324 device_map_stage(This, vsampler_idx, start);
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3327 --start;
3328 break;
3331 --start;
3337 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3339 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3340 BOOL vs = use_vs(This->stateBlock);
3341 BOOL ps = use_ps(This->stateBlock);
3343 * Rules are:
3344 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3345 * that would be really messy and require shader recompilation
3346 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3347 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3349 if (ps) device_map_psamplers(This, gl_info);
3350 else device_map_fixed_function_samplers(This, gl_info);
3352 if (vs) device_map_vsamplers(This, ps, gl_info);
3355 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3357 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3358 This->updateStateBlock->pixelShader = pShader;
3359 This->updateStateBlock->changed.pixelShader = TRUE;
3361 /* Handle recording of state blocks */
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3366 if (This->isRecordingState) {
3367 TRACE("Recording... not performing anything\n");
3368 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3369 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3370 return WINED3D_OK;
3373 if(pShader == oldShader) {
3374 TRACE("App is setting the old pixel shader over, nothing to do\n");
3375 return WINED3D_OK;
3378 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3379 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3381 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3384 return WINED3D_OK;
3387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3390 if (NULL == ppShader) {
3391 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3392 return WINED3DERR_INVALIDCALL;
3395 *ppShader = This->stateBlock->pixelShader;
3396 if (NULL != *ppShader) {
3397 IWineD3DPixelShader_AddRef(*ppShader);
3399 TRACE("(%p) : returning %p\n", This, *ppShader);
3400 return WINED3D_OK;
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3404 IWineD3DDevice *iface,
3405 UINT start,
3406 CONST BOOL *srcData,
3407 UINT count) {
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3412 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3413 iface, srcData, start, count);
3415 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3417 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3418 for (i = 0; i < cnt; i++)
3419 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3421 for (i = start; i < cnt + start; ++i) {
3422 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3425 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3427 return WINED3D_OK;
3430 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3431 IWineD3DDevice *iface,
3432 UINT start,
3433 BOOL *dstData,
3434 UINT count) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 int cnt = min(count, MAX_CONST_B - start);
3439 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3440 iface, dstData, start, count);
3442 if (dstData == NULL || cnt < 0)
3443 return WINED3DERR_INVALIDCALL;
3445 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3446 return WINED3D_OK;
3449 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3450 IWineD3DDevice *iface,
3451 UINT start,
3452 CONST int *srcData,
3453 UINT count) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3458 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3459 iface, srcData, start, count);
3461 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3463 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3464 for (i = 0; i < cnt; i++)
3465 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3466 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3468 for (i = start; i < cnt + start; ++i) {
3469 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3472 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3478 IWineD3DDevice *iface,
3479 UINT start,
3480 int *dstData,
3481 UINT count) {
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 int cnt = min(count, MAX_CONST_I - start);
3486 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3487 iface, dstData, start, count);
3489 if (dstData == NULL || cnt < 0)
3490 return WINED3DERR_INVALIDCALL;
3492 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3493 return WINED3D_OK;
3496 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3497 IWineD3DDevice *iface,
3498 UINT start,
3499 CONST float *srcData,
3500 UINT count) {
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3503 UINT i;
3505 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3506 iface, srcData, start, count);
3508 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3509 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3510 return WINED3DERR_INVALIDCALL;
3512 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3513 if(TRACE_ON(d3d)) {
3514 for (i = 0; i < count; i++)
3515 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3516 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3519 if (!This->isRecordingState)
3521 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3525 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3526 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3528 return WINED3D_OK;
3531 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3532 IWineD3DDevice *iface,
3533 UINT start,
3534 float *dstData,
3535 UINT count) {
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3538 int cnt = min(count, This->d3d_pshader_constantF - start);
3540 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3541 iface, dstData, start, count);
3543 if (dstData == NULL || cnt < 0)
3544 return WINED3DERR_INVALIDCALL;
3546 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3547 return WINED3D_OK;
3550 /* Context activation is done by the caller. */
3551 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3552 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3553 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3554 DWORD DestFVF)
3556 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3557 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3558 unsigned int i;
3559 WINED3DVIEWPORT vp;
3560 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3561 BOOL doClip;
3562 DWORD numTextures;
3564 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3566 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3569 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3571 ERR("Source has no position mask\n");
3572 return WINED3DERR_INVALIDCALL;
3575 /* We might access VBOs from this code, so hold the lock */
3576 ENTER_GL();
3578 if (dest->resource.allocatedMemory == NULL) {
3579 buffer_get_sysmem(dest);
3582 /* Get a pointer into the destination vbo(create one if none exists) and
3583 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3585 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3587 dest->flags |= WINED3D_BUFFER_CREATEBO;
3588 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3591 if (dest->buffer_object)
3593 unsigned char extrabytes = 0;
3594 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3595 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3596 * this may write 4 extra bytes beyond the area that should be written
3598 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3599 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3600 if(!dest_conv_addr) {
3601 ERR("Out of memory\n");
3602 /* Continue without storing converted vertices */
3604 dest_conv = dest_conv_addr;
3607 /* Should I clip?
3608 * a) WINED3DRS_CLIPPING is enabled
3609 * b) WINED3DVOP_CLIP is passed
3611 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3612 static BOOL warned = FALSE;
3614 * The clipping code is not quite correct. Some things need
3615 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3616 * so disable clipping for now.
3617 * (The graphics in Half-Life are broken, and my processvertices
3618 * test crashes with IDirect3DDevice3)
3619 doClip = TRUE;
3621 doClip = FALSE;
3622 if(!warned) {
3623 warned = TRUE;
3624 FIXME("Clipping is broken and disabled for now\n");
3626 } else doClip = FALSE;
3627 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3629 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3630 WINED3DTS_VIEW,
3631 &view_mat);
3632 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3633 WINED3DTS_PROJECTION,
3634 &proj_mat);
3635 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3636 WINED3DTS_WORLDMATRIX(0),
3637 &world_mat);
3639 TRACE("View mat:\n");
3640 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3641 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3642 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3643 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3645 TRACE("Proj mat:\n");
3646 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3647 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3648 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3649 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3651 TRACE("World mat:\n");
3652 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3653 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3654 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3655 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3657 /* Get the viewport */
3658 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3659 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3660 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3662 multiply_matrix(&mat,&view_mat,&world_mat);
3663 multiply_matrix(&mat,&proj_mat,&mat);
3665 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3667 for (i = 0; i < dwCount; i+= 1) {
3668 unsigned int tex_index;
3670 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3671 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3672 /* The position first */
3673 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3674 const float *p = (const float *)(element->data + i * element->stride);
3675 float x, y, z, rhw;
3676 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3678 /* Multiplication with world, view and projection matrix */
3679 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
3680 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
3681 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
3682 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
3684 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3686 /* WARNING: The following things are taken from d3d7 and were not yet checked
3687 * against d3d8 or d3d9!
3690 /* Clipping conditions: From msdn
3692 * A vertex is clipped if it does not match the following requirements
3693 * -rhw < x <= rhw
3694 * -rhw < y <= rhw
3695 * 0 < z <= rhw
3696 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3698 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3699 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3703 if( !doClip ||
3704 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3705 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3706 ( rhw > eps ) ) ) {
3708 /* "Normal" viewport transformation (not clipped)
3709 * 1) The values are divided by rhw
3710 * 2) The y axis is negative, so multiply it with -1
3711 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3712 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3713 * 4) Multiply x with Width/2 and add Width/2
3714 * 5) The same for the height
3715 * 6) Add the viewpoint X and Y to the 2D coordinates and
3716 * The minimum Z value to z
3717 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3719 * Well, basically it's simply a linear transformation into viewport
3720 * coordinates
3723 x /= rhw;
3724 y /= rhw;
3725 z /= rhw;
3727 y *= -1;
3729 x *= vp.Width / 2;
3730 y *= vp.Height / 2;
3731 z *= vp.MaxZ - vp.MinZ;
3733 x += vp.Width / 2 + vp.X;
3734 y += vp.Height / 2 + vp.Y;
3735 z += vp.MinZ;
3737 rhw = 1 / rhw;
3738 } else {
3739 /* That vertex got clipped
3740 * Contrary to OpenGL it is not dropped completely, it just
3741 * undergoes a different calculation.
3743 TRACE("Vertex got clipped\n");
3744 x += rhw;
3745 y += rhw;
3747 x /= 2;
3748 y /= 2;
3750 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3751 * outside of the main vertex buffer memory. That needs some more
3752 * investigation...
3756 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3759 ( (float *) dest_ptr)[0] = x;
3760 ( (float *) dest_ptr)[1] = y;
3761 ( (float *) dest_ptr)[2] = z;
3762 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3764 dest_ptr += 3 * sizeof(float);
3766 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3767 dest_ptr += sizeof(float);
3770 if(dest_conv) {
3771 float w = 1 / rhw;
3772 ( (float *) dest_conv)[0] = x * w;
3773 ( (float *) dest_conv)[1] = y * w;
3774 ( (float *) dest_conv)[2] = z * w;
3775 ( (float *) dest_conv)[3] = w;
3777 dest_conv += 3 * sizeof(float);
3779 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3780 dest_conv += sizeof(float);
3784 if (DestFVF & WINED3DFVF_PSIZE) {
3785 dest_ptr += sizeof(DWORD);
3786 if(dest_conv) dest_conv += sizeof(DWORD);
3788 if (DestFVF & WINED3DFVF_NORMAL) {
3789 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3790 const float *normal = (const float *)(element->data + i * element->stride);
3791 /* AFAIK this should go into the lighting information */
3792 FIXME("Didn't expect the destination to have a normal\n");
3793 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3794 if(dest_conv) {
3795 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3799 if (DestFVF & WINED3DFVF_DIFFUSE) {
3800 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3801 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3802 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3804 static BOOL warned = FALSE;
3806 if(!warned) {
3807 ERR("No diffuse color in source, but destination has one\n");
3808 warned = TRUE;
3811 *( (DWORD *) dest_ptr) = 0xffffffff;
3812 dest_ptr += sizeof(DWORD);
3814 if(dest_conv) {
3815 *( (DWORD *) dest_conv) = 0xffffffff;
3816 dest_conv += sizeof(DWORD);
3819 else {
3820 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3821 if(dest_conv) {
3822 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3823 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3824 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3825 dest_conv += sizeof(DWORD);
3830 if (DestFVF & WINED3DFVF_SPECULAR)
3832 /* What's the color value in the feedback buffer? */
3833 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3834 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3835 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3837 static BOOL warned = FALSE;
3839 if(!warned) {
3840 ERR("No specular color in source, but destination has one\n");
3841 warned = TRUE;
3844 *( (DWORD *) dest_ptr) = 0xFF000000;
3845 dest_ptr += sizeof(DWORD);
3847 if(dest_conv) {
3848 *( (DWORD *) dest_conv) = 0xFF000000;
3849 dest_conv += sizeof(DWORD);
3852 else {
3853 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3854 if(dest_conv) {
3855 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3856 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3857 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3858 dest_conv += sizeof(DWORD);
3863 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3864 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3865 const float *tex_coord = (const float *)(element->data + i * element->stride);
3866 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3868 ERR("No source texture, but destination requests one\n");
3869 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3870 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3872 else {
3873 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3874 if(dest_conv) {
3875 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3881 if(dest_conv) {
3882 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3883 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3884 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3885 dwCount * get_flexible_vertex_size(DestFVF),
3886 dest_conv_addr));
3887 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3888 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3891 LEAVE_GL();
3893 return WINED3D_OK;
3895 #undef copy_and_next
3897 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3898 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3899 DWORD DestFVF)
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 struct wined3d_stream_info stream_info;
3903 struct wined3d_context *context;
3904 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3905 HRESULT hr;
3907 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3909 if(pVertexDecl) {
3910 ERR("Output vertex declaration not implemented yet\n");
3913 /* Need any context to write to the vbo. */
3914 context = context_acquire(This, NULL);
3916 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3917 * control the streamIsUP flag, thus restore it afterwards.
3919 This->stateBlock->streamIsUP = FALSE;
3920 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3921 This->stateBlock->streamIsUP = streamWasUP;
3923 if(vbo || SrcStartIndex) {
3924 unsigned int i;
3925 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3926 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3928 * Also get the start index in, but only loop over all elements if there's something to add at all.
3930 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3932 struct wined3d_stream_info_element *e;
3934 if (!(stream_info.use_map & (1 << i))) continue;
3936 e = &stream_info.elements[i];
3937 if (e->buffer_object)
3939 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3940 e->buffer_object = 0;
3941 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3942 ENTER_GL();
3943 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3944 vb->buffer_object = 0;
3945 LEAVE_GL();
3947 if (e->data) e->data += e->stride * SrcStartIndex;
3951 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3952 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3954 context_release(context);
3956 return hr;
3959 /*****
3960 * Get / Set Texture Stage States
3961 * TODO: Verify against dx9 definitions
3962 *****/
3963 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3966 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3968 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3970 if (Stage >= gl_info->limits.texture_stages)
3972 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3973 Stage, gl_info->limits.texture_stages - 1);
3974 return WINED3D_OK;
3977 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3978 This->updateStateBlock->textureState[Stage][Type] = Value;
3980 if (This->isRecordingState) {
3981 TRACE("Recording... not performing anything\n");
3982 return WINED3D_OK;
3985 /* Checked after the assignments to allow proper stateblock recording */
3986 if(oldValue == Value) {
3987 TRACE("App is setting the old value over, nothing to do\n");
3988 return WINED3D_OK;
3991 if(Stage > This->stateBlock->lowest_disabled_stage &&
3992 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3993 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3994 * Changes in other states are important on disabled stages too
3996 return WINED3D_OK;
3999 if(Type == WINED3DTSS_COLOROP) {
4000 unsigned int i;
4002 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4003 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4004 * they have to be disabled
4006 * The current stage is dirtified below.
4008 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4009 TRACE("Additionally dirtifying stage %u\n", i);
4010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4012 This->stateBlock->lowest_disabled_stage = Stage;
4013 TRACE("New lowest disabled: %u\n", Stage);
4014 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4015 /* Previously disabled stage enabled. Stages above it may need enabling
4016 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4017 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4019 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4022 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4024 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4025 break;
4027 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4030 This->stateBlock->lowest_disabled_stage = i;
4031 TRACE("New lowest disabled: %u\n", i);
4035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4037 return WINED3D_OK;
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4043 *pValue = This->updateStateBlock->textureState[Stage][Type];
4044 return WINED3D_OK;
4047 /*****
4048 * Get / Set Texture
4049 *****/
4050 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4051 DWORD stage, IWineD3DBaseTexture *texture)
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4055 IWineD3DBaseTexture *prev;
4057 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4059 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4060 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4062 /* Windows accepts overflowing this array... we do not. */
4063 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4065 WARN("Ignoring invalid stage %u.\n", stage);
4066 return WINED3D_OK;
4069 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4070 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4072 WARN("Rejecting attempt to set scratch texture.\n");
4073 return WINED3DERR_INVALIDCALL;
4076 This->updateStateBlock->changed.textures |= 1 << stage;
4078 prev = This->updateStateBlock->textures[stage];
4079 TRACE("Previous texture %p.\n", prev);
4081 if (texture == prev)
4083 TRACE("App is setting the same texture again, nothing to do.\n");
4084 return WINED3D_OK;
4087 TRACE("Setting new texture to %p.\n", texture);
4088 This->updateStateBlock->textures[stage] = texture;
4090 if (This->isRecordingState)
4092 TRACE("Recording... not performing anything\n");
4094 if (texture) IWineD3DBaseTexture_AddRef(texture);
4095 if (prev) IWineD3DBaseTexture_Release(prev);
4097 return WINED3D_OK;
4100 if (texture)
4102 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4103 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4104 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4106 IWineD3DBaseTexture_AddRef(texture);
4108 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4113 if (!prev && stage < gl_info->limits.texture_stages)
4115 /* The source arguments for color and alpha ops have different
4116 * meanings when a NULL texture is bound, so the COLOROP and
4117 * ALPHAOP have to be dirtified. */
4118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4122 if (bind_count == 1) t->baseTexture.sampler = stage;
4125 if (prev)
4127 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4128 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4130 IWineD3DBaseTexture_Release(prev);
4132 if (!texture && stage < gl_info->limits.texture_stages)
4134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4138 if (bind_count && t->baseTexture.sampler == stage)
4140 unsigned int i;
4142 /* Search for other stages the texture is bound to. Shouldn't
4143 * happen if applications bind textures to a single stage only. */
4144 TRACE("Searching for other stages the texture is bound to.\n");
4145 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4147 if (This->updateStateBlock->textures[i] == prev)
4149 TRACE("Texture is also bound to stage %u.\n", i);
4150 t->baseTexture.sampler = i;
4151 break;
4157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4159 return WINED3D_OK;
4162 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4165 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4167 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4168 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4171 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4172 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4173 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4176 *ppTexture=This->stateBlock->textures[Stage];
4177 if (*ppTexture)
4178 IWineD3DBaseTexture_AddRef(*ppTexture);
4180 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4182 return WINED3D_OK;
4185 /*****
4186 * Get Back Buffer
4187 *****/
4188 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4189 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4191 IWineD3DSwapChain *swapchain;
4192 HRESULT hr;
4194 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4195 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4197 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4198 if (FAILED(hr))
4200 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4201 return hr;
4204 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4205 IWineD3DSwapChain_Release(swapchain);
4206 if (FAILED(hr))
4208 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4209 return hr;
4212 return WINED3D_OK;
4215 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4217 WARN("(%p) : stub, calling idirect3d for now\n", This);
4218 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4221 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4223 IWineD3DSwapChain *swapChain;
4224 HRESULT hr;
4226 if(iSwapChain > 0) {
4227 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4228 if (hr == WINED3D_OK) {
4229 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4230 IWineD3DSwapChain_Release(swapChain);
4231 } else {
4232 FIXME("(%p) Error getting display mode\n", This);
4234 } else {
4235 /* Don't read the real display mode,
4236 but return the stored mode instead. X11 can't change the color
4237 depth, and some apps are pretty angry if they SetDisplayMode from
4238 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4240 Also don't relay to the swapchain because with ddraw it's possible
4241 that there isn't a swapchain at all */
4242 pMode->Width = This->ddraw_width;
4243 pMode->Height = This->ddraw_height;
4244 pMode->Format = This->ddraw_format;
4245 pMode->RefreshRate = 0;
4246 hr = WINED3D_OK;
4249 return hr;
4252 /*****
4253 * Stateblock related functions
4254 *****/
4256 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4258 IWineD3DStateBlock *stateblock;
4259 HRESULT hr;
4261 TRACE("(%p)\n", This);
4263 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4265 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4266 if (FAILED(hr)) return hr;
4268 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4269 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4270 This->isRecordingState = TRUE;
4272 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4274 return WINED3D_OK;
4277 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4279 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4281 if (!This->isRecordingState) {
4282 WARN("(%p) not recording! returning error\n", This);
4283 *ppStateBlock = NULL;
4284 return WINED3DERR_INVALIDCALL;
4287 stateblock_init_contained_states(object);
4289 *ppStateBlock = (IWineD3DStateBlock*) object;
4290 This->isRecordingState = FALSE;
4291 This->updateStateBlock = This->stateBlock;
4292 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4293 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4294 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4295 return WINED3D_OK;
4298 /*****
4299 * Scene related functions
4300 *****/
4301 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4302 /* At the moment we have no need for any functionality at the beginning
4303 of a scene */
4304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 TRACE("(%p)\n", This);
4307 if(This->inScene) {
4308 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4309 return WINED3DERR_INVALIDCALL;
4311 This->inScene = TRUE;
4312 return WINED3D_OK;
4315 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 struct wined3d_context *context;
4320 TRACE("(%p)\n", This);
4322 if(!This->inScene) {
4323 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4324 return WINED3DERR_INVALIDCALL;
4327 context = context_acquire(This, NULL);
4328 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4329 wglFlush();
4330 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4331 * fails. */
4332 context_release(context);
4334 This->inScene = FALSE;
4335 return WINED3D_OK;
4338 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4339 const RECT *pSourceRect, const RECT *pDestRect,
4340 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4342 IWineD3DSwapChain *swapChain = NULL;
4343 int i;
4344 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4346 TRACE("iface %p.\n", iface);
4348 for(i = 0 ; i < swapchains ; i ++) {
4350 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4351 TRACE("presentinng chain %d, %p\n", i, swapChain);
4352 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4353 IWineD3DSwapChain_Release(swapChain);
4356 return WINED3D_OK;
4359 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
4361 /* partial draw rect */
4362 if (draw_rect->left || draw_rect->top
4363 || draw_rect->right < target->currentDesc.Width
4364 || draw_rect->bottom < target->currentDesc.Height)
4365 return FALSE;
4367 /* partial clear rect */
4368 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
4369 || clear_rect->right < target->currentDesc.Width
4370 || clear_rect->bottom < target->currentDesc.Height))
4371 return FALSE;
4373 return TRUE;
4376 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
4377 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
4379 RECT current_rect, r;
4381 if (ds->Flags & location)
4382 SetRect(&current_rect, 0, 0,
4383 ds->ds_current_size.cx,
4384 ds->ds_current_size.cy);
4385 else
4386 SetRectEmpty(&current_rect);
4388 IntersectRect(&r, draw_rect, &current_rect);
4389 if (EqualRect(&r, draw_rect))
4391 /* current_rect ⊇ draw_rect, modify only. */
4392 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4393 return;
4396 if (EqualRect(&r, &current_rect))
4398 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
4400 if (!clear_rect)
4402 /* Full clear, modify only. */
4403 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4404 return;
4407 IntersectRect(&r, draw_rect, clear_rect);
4408 if (EqualRect(&r, draw_rect))
4410 /* clear_rect ⊇ draw_rect, modify only. */
4411 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4412 return;
4416 /* Full load. */
4417 surface_load_ds_location(ds, context, location);
4418 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4421 /* Not called from the VTable (internal subroutine) */
4422 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4423 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4425 const RECT *clear_rect = (Count > 0 && pRects) ? (const RECT *)pRects : NULL;
4426 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4427 GLbitfield glMask = 0;
4428 unsigned int i;
4429 UINT drawable_width, drawable_height;
4430 struct wined3d_context *context;
4431 RECT draw_rect;
4433 device_get_draw_rect(This, &draw_rect);
4435 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4436 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4437 * for the cleared parts, and the untouched parts.
4439 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4440 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4441 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4442 * checking all this if the dest surface is in the drawable anyway.
4444 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4446 if (!is_full_clear(target, &draw_rect, clear_rect))
4447 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4450 context = context_acquire(This, target);
4451 if (!context->valid)
4453 context_release(context);
4454 WARN("Invalid context, skipping clear.\n");
4455 return WINED3D_OK;
4458 context_apply_clear_state(context, This, target, depth_stencil);
4460 target->get_drawable_size(context, &drawable_width, &drawable_height);
4462 ENTER_GL();
4464 /* Only set the values up once, as they are not changing */
4465 if (Flags & WINED3DCLEAR_STENCIL)
4467 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4469 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4472 glStencilMask(~0U);
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4474 glClearStencil(Stencil);
4475 checkGLcall("glClearStencil");
4476 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4479 if (Flags & WINED3DCLEAR_ZBUFFER)
4481 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4483 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4484 device_switch_onscreen_ds(This, context, depth_stencil);
4485 prepare_ds_clear(depth_stencil, context, location, &draw_rect, Count, clear_rect);
4487 glDepthMask(GL_TRUE);
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4489 glClearDepth(Z);
4490 checkGLcall("glClearDepth");
4491 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4494 if (Flags & WINED3DCLEAR_TARGET)
4496 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4498 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4503 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4504 checkGLcall("glClearColor");
4505 glMask = glMask | GL_COLOR_BUFFER_BIT;
4508 if (!clear_rect)
4510 if (context->render_offscreen)
4512 glScissor(draw_rect.left, draw_rect.top,
4513 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4515 else
4517 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
4518 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4520 checkGLcall("glScissor");
4521 glClear(glMask);
4522 checkGLcall("glClear");
4524 else
4526 RECT current_rect;
4528 /* Now process each rect in turn. */
4529 for (i = 0; i < Count; ++i)
4531 /* Note gl uses lower left, width/height */
4532 IntersectRect(&current_rect, &draw_rect, &clear_rect[i]);
4534 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
4535 wine_dbgstr_rect(&clear_rect[i]),
4536 wine_dbgstr_rect(&current_rect));
4538 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4539 * The rectangle is not cleared, no error is returned, but further rectanlges are
4540 * still cleared if they are valid. */
4541 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
4543 TRACE("Rectangle with negative dimensions, ignoring.\n");
4544 continue;
4547 if (context->render_offscreen)
4549 glScissor(current_rect.left, current_rect.top,
4550 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4552 else
4554 glScissor(current_rect.left, drawable_height - current_rect.bottom,
4555 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4557 checkGLcall("glScissor");
4559 glClear(glMask);
4560 checkGLcall("glClear");
4564 LEAVE_GL();
4566 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4567 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4568 wglFlush(); /* Flush to ensure ordering across contexts. */
4570 context_release(context);
4572 return WINED3D_OK;
4575 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4576 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4581 Count, pRects, Flags, Color, Z, Stencil);
4583 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4585 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4586 /* TODO: What about depth stencil buffers without stencil bits? */
4587 return WINED3DERR_INVALIDCALL;
4590 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4593 /*****
4594 * Drawing functions
4595 *****/
4597 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4598 WINED3DPRIMITIVETYPE primitive_type)
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4604 This->updateStateBlock->changed.primitive_type = TRUE;
4605 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4608 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4609 WINED3DPRIMITIVETYPE *primitive_type)
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4613 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4615 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4617 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4620 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4626 if(!This->stateBlock->vertexDecl) {
4627 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4628 return WINED3DERR_INVALIDCALL;
4631 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4632 if(This->stateBlock->streamIsUP) {
4633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4634 This->stateBlock->streamIsUP = FALSE;
4637 if(This->stateBlock->loadBaseVertexIndex != 0) {
4638 This->stateBlock->loadBaseVertexIndex = 0;
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4641 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4642 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4643 return WINED3D_OK;
4646 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 UINT idxStride = 2;
4650 IWineD3DBuffer *pIB;
4651 GLuint vbo;
4653 pIB = This->stateBlock->pIndexData;
4654 if (!pIB) {
4655 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4656 * without an index buffer set. (The first time at least...)
4657 * D3D8 simply dies, but I doubt it can do much harm to return
4658 * D3DERR_INVALIDCALL there as well. */
4659 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4660 return WINED3DERR_INVALIDCALL;
4663 if(!This->stateBlock->vertexDecl) {
4664 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4665 return WINED3DERR_INVALIDCALL;
4668 if(This->stateBlock->streamIsUP) {
4669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4670 This->stateBlock->streamIsUP = FALSE;
4672 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4674 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4676 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4677 idxStride = 2;
4678 } else {
4679 idxStride = 4;
4682 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4683 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4687 drawPrimitive(iface, index_count, startIndex, idxStride,
4688 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4690 return WINED3D_OK;
4693 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4694 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4697 IWineD3DBuffer *vb;
4699 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4700 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4702 if(!This->stateBlock->vertexDecl) {
4703 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4704 return WINED3DERR_INVALIDCALL;
4707 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4708 vb = This->stateBlock->streamSource[0];
4709 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4710 if (vb) IWineD3DBuffer_Release(vb);
4711 This->stateBlock->streamOffset[0] = 0;
4712 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4713 This->stateBlock->streamIsUP = TRUE;
4714 This->stateBlock->loadBaseVertexIndex = 0;
4716 /* TODO: Only mark dirty if drawing from a different UP address */
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4719 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4721 /* MSDN specifies stream zero settings must be set to NULL */
4722 This->stateBlock->streamStride[0] = 0;
4723 This->stateBlock->streamSource[0] = NULL;
4725 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4726 * the new stream sources or use UP drawing again
4728 return WINED3D_OK;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4732 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4733 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4735 int idxStride;
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 IWineD3DBuffer *vb;
4738 IWineD3DBuffer *ib;
4740 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4741 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4743 if(!This->stateBlock->vertexDecl) {
4744 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4745 return WINED3DERR_INVALIDCALL;
4748 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4749 idxStride = 2;
4750 } else {
4751 idxStride = 4;
4754 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4755 vb = This->stateBlock->streamSource[0];
4756 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4757 if (vb) IWineD3DBuffer_Release(vb);
4758 This->stateBlock->streamIsUP = TRUE;
4759 This->stateBlock->streamOffset[0] = 0;
4760 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4762 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4763 This->stateBlock->baseVertexIndex = 0;
4764 This->stateBlock->loadBaseVertexIndex = 0;
4765 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4769 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4771 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4772 This->stateBlock->streamSource[0] = NULL;
4773 This->stateBlock->streamStride[0] = 0;
4774 ib = This->stateBlock->pIndexData;
4775 if(ib) {
4776 IWineD3DBuffer_Release(ib);
4777 This->stateBlock->pIndexData = NULL;
4779 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4780 * SetStreamSource to specify a vertex buffer
4783 return WINED3D_OK;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4787 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4791 /* Mark the state dirty until we have nicer tracking
4792 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4793 * that value.
4795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4797 This->stateBlock->baseVertexIndex = 0;
4798 This->up_strided = DrawPrimStrideData;
4799 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4800 This->up_strided = NULL;
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4805 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4806 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4809 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4811 /* Mark the state dirty until we have nicer tracking
4812 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4813 * that value.
4815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4817 This->stateBlock->streamIsUP = TRUE;
4818 This->stateBlock->baseVertexIndex = 0;
4819 This->up_strided = DrawPrimStrideData;
4820 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4821 This->up_strided = NULL;
4822 return WINED3D_OK;
4825 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4826 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4827 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4829 WINED3DLOCKED_BOX src;
4830 WINED3DLOCKED_BOX dst;
4831 HRESULT hr;
4833 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4834 iface, pSourceVolume, pDestinationVolume);
4836 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4837 * dirtification to improve loading performance.
4839 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4840 if(FAILED(hr)) return hr;
4841 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4842 if(FAILED(hr)) {
4843 IWineD3DVolume_UnlockBox(pSourceVolume);
4844 return hr;
4847 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4849 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4850 if(FAILED(hr)) {
4851 IWineD3DVolume_UnlockBox(pSourceVolume);
4852 } else {
4853 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4855 return hr;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4859 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4861 unsigned int level_count, i;
4862 WINED3DRESOURCETYPE type;
4863 HRESULT hr;
4865 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4867 /* Verify that the source and destination textures are non-NULL. */
4868 if (!src_texture || !dst_texture)
4870 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4871 return WINED3DERR_INVALIDCALL;
4874 if (src_texture == dst_texture)
4876 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4877 return WINED3DERR_INVALIDCALL;
4880 /* Verify that the source and destination textures are the same type. */
4881 type = IWineD3DBaseTexture_GetType(src_texture);
4882 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4884 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4885 return WINED3DERR_INVALIDCALL;
4888 /* Check that both textures have the identical numbers of levels. */
4889 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4890 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4892 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4893 return WINED3DERR_INVALIDCALL;
4896 /* Make sure that the destination texture is loaded. */
4897 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4899 /* Update every surface level of the texture. */
4900 switch (type)
4902 case WINED3DRTYPE_TEXTURE:
4904 IWineD3DSurface *src_surface;
4905 IWineD3DSurface *dst_surface;
4907 for (i = 0; i < level_count; ++i)
4909 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4910 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
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;
4920 break;
4923 case WINED3DRTYPE_CUBETEXTURE:
4925 IWineD3DSurface *src_surface;
4926 IWineD3DSurface *dst_surface;
4927 WINED3DCUBEMAP_FACES face;
4929 for (i = 0; i < level_count; ++i)
4931 /* Update each cube face. */
4932 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4934 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4935 face, i, &src_surface);
4936 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4937 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4938 face, i, &dst_surface);
4939 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4940 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4941 IWineD3DSurface_Release(dst_surface);
4942 IWineD3DSurface_Release(src_surface);
4943 if (FAILED(hr))
4945 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4946 return hr;
4950 break;
4953 case WINED3DRTYPE_VOLUMETEXTURE:
4955 IWineD3DVolume *src_volume;
4956 IWineD3DVolume *dst_volume;
4958 for (i = 0; i < level_count; ++i)
4960 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4961 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4962 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4963 IWineD3DVolume_Release(dst_volume);
4964 IWineD3DVolume_Release(src_volume);
4965 if (FAILED(hr))
4967 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4968 return hr;
4971 break;
4974 default:
4975 FIXME("Unsupported texture type %#x.\n", type);
4976 return WINED3DERR_INVALIDCALL;
4979 return WINED3D_OK;
4982 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4983 IWineD3DSwapChain *swapChain;
4984 HRESULT hr;
4985 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4986 if(hr == WINED3D_OK) {
4987 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4988 IWineD3DSwapChain_Release(swapChain);
4990 return hr;
4993 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 IWineD3DBaseTextureImpl *texture;
4996 DWORD i;
4998 TRACE("(%p) : %p\n", This, pNumPasses);
5000 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5001 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5002 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5003 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5005 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5006 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5007 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5010 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5011 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5013 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5014 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5015 return E_FAIL;
5017 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5018 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5019 return E_FAIL;
5021 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5022 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5023 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5024 return E_FAIL;
5028 /* return a sensible default */
5029 *pNumPasses = 1;
5031 TRACE("returning D3D_OK\n");
5032 return WINED3D_OK;
5035 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5037 int i;
5039 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5041 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5042 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5043 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5045 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5050 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5052 int j;
5053 UINT NewSize;
5054 PALETTEENTRY **palettes;
5056 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5058 if (PaletteNumber >= MAX_PALETTES) {
5059 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5060 return WINED3DERR_INVALIDCALL;
5063 if (PaletteNumber >= This->NumberOfPalettes) {
5064 NewSize = This->NumberOfPalettes;
5065 do {
5066 NewSize *= 2;
5067 } while(PaletteNumber >= NewSize);
5068 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5069 if (!palettes) {
5070 ERR("Out of memory!\n");
5071 return E_OUTOFMEMORY;
5073 This->palettes = palettes;
5074 This->NumberOfPalettes = NewSize;
5077 if (!This->palettes[PaletteNumber]) {
5078 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5079 if (!This->palettes[PaletteNumber]) {
5080 ERR("Out of memory!\n");
5081 return E_OUTOFMEMORY;
5085 for (j = 0; j < 256; ++j) {
5086 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5087 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5088 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5089 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5091 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5092 TRACE("(%p) : returning\n", This);
5093 return WINED3D_OK;
5096 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5098 int j;
5099 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5100 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5101 /* What happens in such situation isn't documented; Native seems to silently abort
5102 on such conditions. Return Invalid Call. */
5103 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5104 return WINED3DERR_INVALIDCALL;
5106 for (j = 0; j < 256; ++j) {
5107 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5108 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5109 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5110 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5112 TRACE("(%p) : returning\n", This);
5113 return WINED3D_OK;
5116 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5118 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5119 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5120 (tested with reference rasterizer). Return Invalid Call. */
5121 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5122 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5123 return WINED3DERR_INVALIDCALL;
5125 /*TODO: stateblocks */
5126 if (This->currentPalette != PaletteNumber) {
5127 This->currentPalette = PaletteNumber;
5128 dirtify_p8_texture_samplers(This);
5130 TRACE("(%p) : returning\n", This);
5131 return WINED3D_OK;
5134 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 if (PaletteNumber == NULL) {
5137 WARN("(%p) : returning Invalid Call\n", This);
5138 return WINED3DERR_INVALIDCALL;
5140 /*TODO: stateblocks */
5141 *PaletteNumber = This->currentPalette;
5142 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5143 return WINED3D_OK;
5146 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 static BOOL warned;
5149 if (!warned)
5151 FIXME("(%p) : stub\n", This);
5152 warned = TRUE;
5155 This->softwareVertexProcessing = bSoftware;
5156 return WINED3D_OK;
5160 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5162 static BOOL warned;
5163 if (!warned)
5165 FIXME("(%p) : stub\n", This);
5166 warned = TRUE;
5168 return This->softwareVertexProcessing;
5171 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5172 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5174 IWineD3DSwapChain *swapchain;
5175 HRESULT hr;
5177 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5178 iface, swapchain_idx, raster_status);
5180 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5181 if (FAILED(hr))
5183 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5184 return hr;
5187 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5188 IWineD3DSwapChain_Release(swapchain);
5189 if (FAILED(hr))
5191 WARN("Failed to get raster status, hr %#x.\n", hr);
5192 return hr;
5195 return WINED3D_OK;
5198 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5200 static BOOL warned;
5201 if(nSegments != 0.0f) {
5202 if (!warned)
5204 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5205 warned = TRUE;
5208 return WINED3D_OK;
5211 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5213 static BOOL warned;
5214 if (!warned)
5216 FIXME("iface %p stub!\n", iface);
5217 warned = TRUE;
5219 return 0.0f;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5223 IWineD3DSurface *src_surface, const RECT *src_rect,
5224 IWineD3DSurface *dst_surface, const POINT *dst_point)
5226 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5227 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5229 const struct wined3d_format_desc *src_format;
5230 const struct wined3d_format_desc *dst_format;
5231 struct wined3d_context *context;
5232 const unsigned char *data;
5233 UINT update_w, update_h;
5234 CONVERT_TYPES convert;
5235 UINT src_w, src_h;
5236 UINT dst_x, dst_y;
5237 DWORD sampler;
5238 struct wined3d_format_desc dummy_desc;
5240 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5241 iface, src_surface, wine_dbgstr_rect(src_rect),
5242 dst_surface, wine_dbgstr_point(dst_point));
5244 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5246 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5247 src_surface, dst_surface);
5248 return WINED3DERR_INVALIDCALL;
5251 src_format = src_impl->resource.format_desc;
5252 dst_format = dst_impl->resource.format_desc;
5254 if (src_format->format != dst_format->format)
5256 WARN("Source and destination surfaces should have the same format.\n");
5257 return WINED3DERR_INVALIDCALL;
5260 dst_x = dst_point ? dst_point->x : 0;
5261 dst_y = dst_point ? dst_point->y : 0;
5263 /* This call loads the OpenGL surface directly, instead of copying the
5264 * surface to the destination's sysmem copy. If surface conversion is
5265 * needed, use BltFast instead to copy in sysmem and use regular surface
5266 * loading. */
5267 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5268 if (convert != NO_CONVERSION)
5269 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5271 context = context_acquire(This, NULL);
5273 ENTER_GL();
5274 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5275 checkGLcall("glActiveTextureARB");
5276 LEAVE_GL();
5278 /* Make sure the surface is loaded and up to date */
5279 surface_internal_preload(dst_impl, SRGB_RGB);
5280 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5282 src_w = src_impl->currentDesc.Width;
5283 src_h = src_impl->currentDesc.Height;
5284 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5285 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5287 data = IWineD3DSurface_GetData(src_surface);
5288 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5290 ENTER_GL();
5292 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5294 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5295 UINT row_count = update_h / src_format->block_height;
5296 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5298 if (src_rect)
5300 data += (src_rect->top / src_format->block_height) * src_pitch;
5301 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5304 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5305 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5306 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5308 if (row_length == src_pitch)
5310 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5311 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5313 else
5315 UINT row, y;
5317 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5318 * can't use the unpack row length like below. */
5319 for (row = 0, y = dst_y; row < row_count; ++row)
5321 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5322 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5323 y += src_format->block_height;
5324 data += src_pitch;
5327 checkGLcall("glCompressedTexSubImage2DARB");
5329 else
5331 if (src_rect)
5333 data += src_rect->top * src_w * src_format->byte_count;
5334 data += src_rect->left * src_format->byte_count;
5337 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5338 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5339 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5341 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5342 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5343 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5344 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5345 checkGLcall("glTexSubImage2D");
5348 LEAVE_GL();
5349 context_release(context);
5351 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5352 sampler = This->rev_tex_unit_map[0];
5353 if (sampler != WINED3D_UNMAPPED_STAGE)
5355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5358 return WINED3D_OK;
5361 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5363 struct WineD3DRectPatch *patch;
5364 GLenum old_primitive_type;
5365 unsigned int i;
5366 struct list *e;
5367 BOOL found;
5368 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5370 if(!(Handle || pRectPatchInfo)) {
5371 /* TODO: Write a test for the return value, thus the FIXME */
5372 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5373 return WINED3DERR_INVALIDCALL;
5376 if(Handle) {
5377 i = PATCHMAP_HASHFUNC(Handle);
5378 found = FALSE;
5379 LIST_FOR_EACH(e, &This->patches[i]) {
5380 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5381 if(patch->Handle == Handle) {
5382 found = TRUE;
5383 break;
5387 if(!found) {
5388 TRACE("Patch does not exist. Creating a new one\n");
5389 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5390 patch->Handle = Handle;
5391 list_add_head(&This->patches[i], &patch->entry);
5392 } else {
5393 TRACE("Found existing patch %p\n", patch);
5395 } else {
5396 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5397 * attributes we have to tesselate, read back, and draw. This needs a patch
5398 * management structure instance. Create one.
5400 * A possible improvement is to check if a vertex shader is used, and if not directly
5401 * draw the patch.
5403 FIXME("Drawing an uncached patch. This is slow\n");
5404 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5407 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5408 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5409 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5410 HRESULT hr;
5411 TRACE("Tesselation density or patch info changed, retesselating\n");
5413 if(pRectPatchInfo) {
5414 patch->RectPatchInfo = *pRectPatchInfo;
5416 patch->numSegs[0] = pNumSegs[0];
5417 patch->numSegs[1] = pNumSegs[1];
5418 patch->numSegs[2] = pNumSegs[2];
5419 patch->numSegs[3] = pNumSegs[3];
5421 hr = tesselate_rectpatch(This, patch);
5422 if(FAILED(hr)) {
5423 WARN("Patch tesselation failed\n");
5425 /* Do not release the handle to store the params of the patch */
5426 if(!Handle) {
5427 HeapFree(GetProcessHeap(), 0, patch);
5429 return hr;
5433 This->currentPatch = patch;
5434 old_primitive_type = This->stateBlock->gl_primitive_type;
5435 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5436 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5437 This->stateBlock->gl_primitive_type = old_primitive_type;
5438 This->currentPatch = NULL;
5440 /* Destroy uncached patches */
5441 if(!Handle) {
5442 HeapFree(GetProcessHeap(), 0, patch->mem);
5443 HeapFree(GetProcessHeap(), 0, patch);
5445 return WINED3D_OK;
5448 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5449 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5451 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5452 iface, handle, segment_count, patch_info);
5454 return WINED3D_OK;
5457 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5459 int i;
5460 struct WineD3DRectPatch *patch;
5461 struct list *e;
5462 TRACE("(%p) Handle(%d)\n", This, Handle);
5464 i = PATCHMAP_HASHFUNC(Handle);
5465 LIST_FOR_EACH(e, &This->patches[i]) {
5466 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5467 if(patch->Handle == Handle) {
5468 TRACE("Deleting patch %p\n", patch);
5469 list_remove(&patch->entry);
5470 HeapFree(GetProcessHeap(), 0, patch->mem);
5471 HeapFree(GetProcessHeap(), 0, patch);
5472 return WINED3D_OK;
5476 /* TODO: Write a test for the return value */
5477 FIXME("Attempt to destroy nonexistent patch\n");
5478 return WINED3DERR_INVALIDCALL;
5481 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5482 const WINED3DRECT *rect, const float color[4])
5484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5485 struct wined3d_context *context;
5487 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5488 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5490 context = context_acquire(This, surface);
5491 context_apply_clear_state(context, This, surface, NULL);
5493 ENTER_GL();
5495 if (rect)
5497 if (surface_is_offscreen(surface))
5498 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5499 else
5500 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5501 rect->x2 - rect->x1, rect->y2 - rect->y1);
5502 checkGLcall("glScissor");
5504 else
5506 glDisable(GL_SCISSOR_TEST);
5509 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5515 glClearColor(color[0], color[1], color[2], color[3]);
5516 glClear(GL_COLOR_BUFFER_BIT);
5517 checkGLcall("glClear");
5519 LEAVE_GL();
5521 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5523 context_release(context);
5526 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5527 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5529 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5530 WINEDDBLTFX BltFx;
5532 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5534 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5535 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5536 return WINED3DERR_INVALIDCALL;
5539 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5540 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5541 color_fill_fbo(iface, surface, pRect, c);
5542 return WINED3D_OK;
5543 } else {
5544 /* Just forward this to the DirectDraw blitting engine */
5545 memset(&BltFx, 0, sizeof(BltFx));
5546 BltFx.dwSize = sizeof(BltFx);
5547 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5548 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5549 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5553 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5554 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5556 IWineD3DResource *resource;
5557 IWineD3DSurfaceImpl *surface;
5558 HRESULT hr;
5560 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5561 if (FAILED(hr))
5563 ERR("Failed to get resource, hr %#x\n", hr);
5564 return;
5567 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5569 FIXME("Only supported on surface resources\n");
5570 IWineD3DResource_Release(resource);
5571 return;
5574 surface = (IWineD3DSurfaceImpl *)resource;
5576 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5578 color_fill_fbo(iface, surface, NULL, color);
5580 else
5582 WINEDDBLTFX BltFx;
5583 WINED3DCOLOR c;
5585 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5587 c = ((DWORD)(color[2] * 255.0f));
5588 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5589 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5590 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5592 /* Just forward this to the DirectDraw blitting engine */
5593 memset(&BltFx, 0, sizeof(BltFx));
5594 BltFx.dwSize = sizeof(BltFx);
5595 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5596 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5597 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5598 if (FAILED(hr))
5600 ERR("Blt failed, hr %#x\n", hr);
5604 IWineD3DResource_Release(resource);
5607 /* rendertarget and depth stencil functions */
5608 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5613 ERR("(%p) : Only %d render targets are supported.\n",
5614 This, This->adapter->gl_info.limits.buffers);
5615 return WINED3DERR_INVALIDCALL;
5618 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5619 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5620 /* Note inc ref on returned surface */
5621 if(*ppRenderTarget != NULL)
5622 IWineD3DSurface_AddRef(*ppRenderTarget);
5623 return WINED3D_OK;
5626 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5627 IWineD3DSurface *front, IWineD3DSurface *back)
5629 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5630 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5631 IWineD3DSwapChainImpl *swapchain;
5632 HRESULT hr;
5634 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5636 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5638 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5639 return hr;
5642 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5644 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5645 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5646 return WINED3DERR_INVALIDCALL;
5649 if (back_impl)
5651 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5653 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5654 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5655 return WINED3DERR_INVALIDCALL;
5658 if (!swapchain->back_buffers)
5660 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5661 if (!swapchain->back_buffers)
5663 ERR("Failed to allocate back buffer array memory.\n");
5664 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5665 return E_OUTOFMEMORY;
5670 if (swapchain->front_buffer != front_impl)
5672 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5674 if (swapchain->front_buffer)
5676 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5677 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5679 swapchain->front_buffer = front_impl;
5681 if (front)
5683 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5684 front_impl->Flags |= SFLAG_SWAPCHAIN;
5688 if (swapchain->back_buffers[0] != back_impl)
5690 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5692 if (swapchain->back_buffers[0])
5694 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5695 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5697 swapchain->back_buffers[0] = back_impl;
5699 if (back)
5701 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5702 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5703 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5704 swapchain->presentParms.BackBufferCount = 1;
5706 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5707 back_impl->Flags |= SFLAG_SWAPCHAIN;
5709 else
5711 swapchain->presentParms.BackBufferCount = 0;
5712 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5713 swapchain->back_buffers = NULL;
5717 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5718 return WINED3D_OK;
5721 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5723 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5724 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5726 if(*ppZStencilSurface != NULL) {
5727 /* Note inc ref on returned surface */
5728 IWineD3DSurface_AddRef(*ppZStencilSurface);
5729 return WINED3D_OK;
5730 } else {
5731 return WINED3DERR_NOTFOUND;
5735 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5736 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5738 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5739 const struct wined3d_gl_info *gl_info;
5740 struct wined3d_context *context;
5741 GLenum gl_filter;
5742 POINT offset = {0, 0};
5743 RECT src_rect, dst_rect;
5745 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5746 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5747 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5749 src_rect = *src_rect_in;
5750 dst_rect = *dst_rect_in;
5752 switch (filter) {
5753 case WINED3DTEXF_LINEAR:
5754 gl_filter = GL_LINEAR;
5755 break;
5757 default:
5758 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5759 case WINED3DTEXF_NONE:
5760 case WINED3DTEXF_POINT:
5761 gl_filter = GL_NEAREST;
5762 break;
5765 /* Make sure the drawables are up-to-date. Note that loading the
5766 * destination surface isn't strictly required if we overwrite the
5767 * entire surface. */
5768 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5769 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5771 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface);
5772 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface);
5773 else context = context_acquire(device, NULL);
5775 if (!context->valid)
5777 context_release(context);
5778 WARN("Invalid context, skipping blit.\n");
5779 return;
5782 gl_info = context->gl_info;
5784 if (!surface_is_offscreen(src_surface))
5786 GLenum buffer = surface_get_gl_buffer(src_surface);
5788 TRACE("Source surface %p is onscreen\n", src_surface);
5790 if(buffer == GL_FRONT) {
5791 RECT windowsize;
5792 UINT h;
5793 ClientToScreen(context->win_handle, &offset);
5794 GetClientRect(context->win_handle, &windowsize);
5795 h = windowsize.bottom - windowsize.top;
5796 src_rect.left -= offset.x; src_rect.right -=offset.x;
5797 src_rect.top = offset.y + h - src_rect.top;
5798 src_rect.bottom = offset.y + h - src_rect.bottom;
5799 } else {
5800 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5801 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5804 ENTER_GL();
5805 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5806 glReadBuffer(buffer);
5807 checkGLcall("glReadBuffer()");
5808 } else {
5809 TRACE("Source surface %p is offscreen\n", src_surface);
5810 ENTER_GL();
5811 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5812 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5813 glReadBuffer(GL_COLOR_ATTACHMENT0);
5814 checkGLcall("glReadBuffer()");
5815 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5817 LEAVE_GL();
5819 /* Attach dst surface to dst fbo */
5820 if (!surface_is_offscreen(dst_surface))
5822 GLenum buffer = surface_get_gl_buffer(dst_surface);
5824 TRACE("Destination surface %p is onscreen\n", dst_surface);
5826 if(buffer == GL_FRONT) {
5827 RECT windowsize;
5828 UINT h;
5829 ClientToScreen(context->win_handle, &offset);
5830 GetClientRect(context->win_handle, &windowsize);
5831 h = windowsize.bottom - windowsize.top;
5832 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5833 dst_rect.top = offset.y + h - dst_rect.top;
5834 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5835 } else {
5836 /* Screen coords = window coords, surface height = window height */
5837 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5838 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5841 ENTER_GL();
5842 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5843 context_set_draw_buffer(context, buffer);
5845 else
5847 TRACE("Destination surface %p is offscreen\n", dst_surface);
5849 ENTER_GL();
5850 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5851 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5852 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5853 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5855 glDisable(GL_SCISSOR_TEST);
5856 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5858 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5859 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5860 checkGLcall("glBlitFramebuffer()");
5862 LEAVE_GL();
5864 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5866 context_release(context);
5868 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5871 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5872 BOOL set_viewport) {
5873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5875 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5877 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5879 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5880 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5881 return WINED3DERR_INVALIDCALL;
5884 /* MSDN says that null disables the render target
5885 but a device must always be associated with a render target
5886 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5888 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5889 FIXME("Trying to set render target 0 to NULL\n");
5890 return WINED3DERR_INVALIDCALL;
5892 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5893 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);
5894 return WINED3DERR_INVALIDCALL;
5897 /* If we are trying to set what we already have, don't bother */
5898 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5900 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5901 return WINED3D_OK;
5903 if (pRenderTarget)
5904 IWineD3DSurface_AddRef(pRenderTarget);
5905 if (This->render_targets[RenderTargetIndex])
5906 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5907 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5909 /* Render target 0 is special */
5910 if(RenderTargetIndex == 0 && set_viewport) {
5911 /* Finally, reset the viewport and scissor rect as the MSDN states.
5912 * Tests show that stateblock recording is ignored, the change goes
5913 * directly into the primary stateblock.
5915 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5916 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5917 This->stateBlock->viewport.X = 0;
5918 This->stateBlock->viewport.Y = 0;
5919 This->stateBlock->viewport.MaxZ = 1.0f;
5920 This->stateBlock->viewport.MinZ = 0.0f;
5921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5923 This->stateBlock->scissorRect.top = 0;
5924 This->stateBlock->scissorRect.left = 0;
5925 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5926 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5929 return WINED3D_OK;
5932 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5934 IWineD3DSurfaceImpl *tmp;
5936 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5938 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5940 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5941 return WINED3D_OK;
5944 if (This->depth_stencil)
5946 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5947 || This->depth_stencil->Flags & SFLAG_DISCARD)
5949 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5950 This->depth_stencil->currentDesc.Width,
5951 This->depth_stencil->currentDesc.Height);
5952 if (This->depth_stencil == This->onscreen_depth_stencil)
5954 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5955 This->onscreen_depth_stencil = NULL;
5960 tmp = This->depth_stencil;
5961 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5962 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5963 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5965 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5967 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5973 return WINED3D_OK;
5976 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5977 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5979 /* TODO: the use of Impl is deprecated. */
5980 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5981 WINED3DLOCKED_RECT lockedRect;
5983 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5985 /* some basic validation checks */
5986 if (This->cursorTexture)
5988 struct wined3d_context *context = context_acquire(This, NULL);
5989 ENTER_GL();
5990 glDeleteTextures(1, &This->cursorTexture);
5991 LEAVE_GL();
5992 context_release(context);
5993 This->cursorTexture = 0;
5996 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5997 This->haveHardwareCursor = TRUE;
5998 else
5999 This->haveHardwareCursor = FALSE;
6001 if(pCursorBitmap) {
6002 WINED3DLOCKED_RECT rect;
6004 /* MSDN: Cursor must be A8R8G8B8 */
6005 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6007 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6008 return WINED3DERR_INVALIDCALL;
6011 /* MSDN: Cursor must be smaller than the display mode */
6012 if(pSur->currentDesc.Width > This->ddraw_width ||
6013 pSur->currentDesc.Height > This->ddraw_height) {
6014 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);
6015 return WINED3DERR_INVALIDCALL;
6018 if (!This->haveHardwareCursor) {
6019 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6021 /* Do not store the surface's pointer because the application may
6022 * release it after setting the cursor image. Windows doesn't
6023 * addref the set surface, so we can't do this either without
6024 * creating circular refcount dependencies. Copy out the gl texture
6025 * instead.
6027 This->cursorWidth = pSur->currentDesc.Width;
6028 This->cursorHeight = pSur->currentDesc.Height;
6029 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6031 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6032 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6033 struct wined3d_context *context;
6034 char *mem, *bits = rect.pBits;
6035 GLint intfmt = format_desc->glInternal;
6036 GLint format = format_desc->glFormat;
6037 GLint type = format_desc->glType;
6038 INT height = This->cursorHeight;
6039 INT width = This->cursorWidth;
6040 INT bpp = format_desc->byte_count;
6041 DWORD sampler;
6042 INT i;
6044 /* Reformat the texture memory (pitch and width can be
6045 * different) */
6046 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6047 for(i = 0; i < height; i++)
6048 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6049 IWineD3DSurface_UnlockRect(pCursorBitmap);
6051 context = context_acquire(This, NULL);
6053 ENTER_GL();
6055 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6057 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6058 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6061 /* Make sure that a proper texture unit is selected */
6062 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6063 checkGLcall("glActiveTextureARB");
6064 sampler = This->rev_tex_unit_map[0];
6065 if (sampler != WINED3D_UNMAPPED_STAGE)
6067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6069 /* Create a new cursor texture */
6070 glGenTextures(1, &This->cursorTexture);
6071 checkGLcall("glGenTextures");
6072 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6073 checkGLcall("glBindTexture");
6074 /* Copy the bitmap memory into the cursor texture */
6075 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6076 HeapFree(GetProcessHeap(), 0, mem);
6077 checkGLcall("glTexImage2D");
6079 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6081 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6082 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6085 LEAVE_GL();
6087 context_release(context);
6089 else
6091 FIXME("A cursor texture was not returned.\n");
6092 This->cursorTexture = 0;
6095 else
6097 /* Draw a hardware cursor */
6098 ICONINFO cursorInfo;
6099 HCURSOR cursor;
6100 /* Create and clear maskBits because it is not needed for
6101 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6102 * chunks. */
6103 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6104 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6105 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6106 WINED3DLOCK_NO_DIRTY_UPDATE |
6107 WINED3DLOCK_READONLY
6109 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6110 pSur->currentDesc.Height);
6112 cursorInfo.fIcon = FALSE;
6113 cursorInfo.xHotspot = XHotSpot;
6114 cursorInfo.yHotspot = YHotSpot;
6115 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6116 1, 1, maskBits);
6117 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6118 1, 32, lockedRect.pBits);
6119 IWineD3DSurface_UnlockRect(pCursorBitmap);
6120 /* Create our cursor and clean up. */
6121 cursor = CreateIconIndirect(&cursorInfo);
6122 SetCursor(cursor);
6123 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6124 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6125 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6126 This->hardwareCursor = cursor;
6127 HeapFree(GetProcessHeap(), 0, maskBits);
6131 This->xHotSpot = XHotSpot;
6132 This->yHotSpot = YHotSpot;
6133 return WINED3D_OK;
6136 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6138 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6140 This->xScreenSpace = XScreenSpace;
6141 This->yScreenSpace = YScreenSpace;
6143 return;
6147 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6149 BOOL oldVisible = This->bCursorVisible;
6150 POINT pt;
6152 TRACE("(%p) : visible(%d)\n", This, bShow);
6155 * When ShowCursor is first called it should make the cursor appear at the OS's last
6156 * known cursor position. Because of this, some applications just repetitively call
6157 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6159 GetCursorPos(&pt);
6160 This->xScreenSpace = pt.x;
6161 This->yScreenSpace = pt.y;
6163 if (This->haveHardwareCursor) {
6164 This->bCursorVisible = bShow;
6165 if (bShow)
6166 SetCursor(This->hardwareCursor);
6167 else
6168 SetCursor(NULL);
6170 else
6172 if (This->cursorTexture)
6173 This->bCursorVisible = bShow;
6176 return oldVisible;
6179 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6180 TRACE("checking resource %p for eviction\n", resource);
6181 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6182 TRACE("Evicting %p\n", resource);
6183 IWineD3DResource_UnLoad(resource);
6185 IWineD3DResource_Release(resource);
6186 return S_OK;
6189 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6191 TRACE("iface %p.\n", iface);
6193 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6194 return WINED3D_OK;
6197 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6199 IWineD3DDeviceImpl *device = surface->resource.device;
6200 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6202 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6203 if(surface->Flags & SFLAG_DIBSECTION) {
6204 /* Release the DC */
6205 SelectObject(surface->hDC, surface->dib.holdbitmap);
6206 DeleteDC(surface->hDC);
6207 /* Release the DIB section */
6208 DeleteObject(surface->dib.DIBsection);
6209 surface->dib.bitmap_data = NULL;
6210 surface->resource.allocatedMemory = NULL;
6211 surface->Flags &= ~SFLAG_DIBSECTION;
6213 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6214 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6215 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6216 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6218 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6219 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6220 } else {
6221 surface->pow2Width = surface->pow2Height = 1;
6222 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6223 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6226 if (surface->texture_name)
6228 struct wined3d_context *context = context_acquire(device, NULL);
6229 ENTER_GL();
6230 glDeleteTextures(1, &surface->texture_name);
6231 LEAVE_GL();
6232 context_release(context);
6233 surface->texture_name = 0;
6234 surface->Flags &= ~SFLAG_CLIENT;
6236 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6237 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6238 surface->Flags |= SFLAG_NONPOW2;
6239 } else {
6240 surface->Flags &= ~SFLAG_NONPOW2;
6242 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6243 surface->resource.allocatedMemory = NULL;
6244 surface->resource.heapMemory = NULL;
6245 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6247 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6248 * to a FBO */
6249 if (!surface_init_sysmem(surface))
6251 return E_OUTOFMEMORY;
6253 return WINED3D_OK;
6256 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6257 TRACE("Unloading resource %p\n", resource);
6258 IWineD3DResource_UnLoad(resource);
6259 IWineD3DResource_Release(resource);
6260 return S_OK;
6263 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6265 UINT i, count;
6266 WINED3DDISPLAYMODE m;
6267 HRESULT hr;
6269 /* All Windowed modes are supported, as is leaving the current mode */
6270 if(pp->Windowed) return TRUE;
6271 if(!pp->BackBufferWidth) return TRUE;
6272 if(!pp->BackBufferHeight) return TRUE;
6274 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6275 for(i = 0; i < count; i++) {
6276 memset(&m, 0, sizeof(m));
6277 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6278 if(FAILED(hr)) {
6279 ERR("EnumAdapterModes failed\n");
6281 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6282 /* Mode found, it is supported */
6283 return TRUE;
6286 /* Mode not found -> not supported */
6287 return FALSE;
6290 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6293 const struct wined3d_gl_info *gl_info;
6294 struct wined3d_context *context;
6295 IWineD3DBaseShaderImpl *shader;
6297 context = context_acquire(This, NULL);
6298 gl_info = context->gl_info;
6300 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6301 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6302 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6305 ENTER_GL();
6306 if(This->depth_blt_texture) {
6307 glDeleteTextures(1, &This->depth_blt_texture);
6308 This->depth_blt_texture = 0;
6310 if (This->depth_blt_rb) {
6311 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6312 This->depth_blt_rb = 0;
6313 This->depth_blt_rb_w = 0;
6314 This->depth_blt_rb_h = 0;
6316 LEAVE_GL();
6318 This->blitter->free_private(iface);
6319 This->frag_pipe->free_private(iface);
6320 This->shader_backend->shader_free_private(iface);
6321 destroy_dummy_textures(This, gl_info);
6323 context_release(context);
6325 while (This->numContexts)
6327 context_destroy(This, This->contexts[0]);
6329 HeapFree(GetProcessHeap(), 0, swapchain->context);
6330 swapchain->context = NULL;
6331 swapchain->num_contexts = 0;
6334 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6337 struct wined3d_context *context;
6338 HRESULT hr;
6339 IWineD3DSurfaceImpl *target;
6341 /* Recreate the primary swapchain's context */
6342 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6343 if (!swapchain->context)
6345 ERR("Failed to allocate memory for swapchain context array.\n");
6346 return E_OUTOFMEMORY;
6349 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6350 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6352 WARN("Failed to create context.\n");
6353 HeapFree(GetProcessHeap(), 0, swapchain->context);
6354 return E_FAIL;
6357 swapchain->context[0] = context;
6358 swapchain->num_contexts = 1;
6359 create_dummy_textures(This);
6360 context_release(context);
6362 hr = This->shader_backend->shader_alloc_private(iface);
6363 if (FAILED(hr))
6365 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6366 goto err;
6369 hr = This->frag_pipe->alloc_private(iface);
6370 if (FAILED(hr))
6372 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6373 This->shader_backend->shader_free_private(iface);
6374 goto err;
6377 hr = This->blitter->alloc_private(iface);
6378 if (FAILED(hr))
6380 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6381 This->frag_pipe->free_private(iface);
6382 This->shader_backend->shader_free_private(iface);
6383 goto err;
6386 return WINED3D_OK;
6388 err:
6389 context_acquire(This, NULL);
6390 destroy_dummy_textures(This, context->gl_info);
6391 context_release(context);
6392 context_destroy(This, context);
6393 HeapFree(GetProcessHeap(), 0, swapchain->context);
6394 swapchain->num_contexts = 0;
6395 return hr;
6398 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6400 IWineD3DSwapChainImpl *swapchain;
6401 HRESULT hr;
6402 BOOL DisplayModeChanged = FALSE;
6403 WINED3DDISPLAYMODE mode;
6404 TRACE("(%p)\n", This);
6406 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6407 if(FAILED(hr)) {
6408 ERR("Failed to get the first implicit swapchain\n");
6409 return hr;
6412 if(!is_display_mode_supported(This, pPresentationParameters)) {
6413 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6414 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6415 pPresentationParameters->BackBufferHeight);
6416 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6417 return WINED3DERR_INVALIDCALL;
6420 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6421 * on an existing gl context, so there's no real need for recreation.
6423 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6425 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6427 TRACE("New params:\n");
6428 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6429 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6430 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6431 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6432 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6433 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6434 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6435 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6436 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6437 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6438 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6439 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6440 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6442 /* No special treatment of these parameters. Just store them */
6443 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6444 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6445 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6446 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6448 /* What to do about these? */
6449 if(pPresentationParameters->BackBufferCount != 0 &&
6450 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6451 ERR("Cannot change the back buffer count yet\n");
6453 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6454 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6455 ERR("Cannot change the back buffer format yet\n");
6457 if(pPresentationParameters->hDeviceWindow != NULL &&
6458 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6459 ERR("Cannot change the device window yet\n");
6461 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6463 HRESULT hrc;
6465 TRACE("Creating the depth stencil buffer\n");
6467 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6468 This->parent,
6469 pPresentationParameters->BackBufferWidth,
6470 pPresentationParameters->BackBufferHeight,
6471 pPresentationParameters->AutoDepthStencilFormat,
6472 pPresentationParameters->MultiSampleType,
6473 pPresentationParameters->MultiSampleQuality,
6474 FALSE,
6475 (IWineD3DSurface **)&This->auto_depth_stencil);
6477 if (FAILED(hrc)) {
6478 ERR("Failed to create the depth stencil buffer\n");
6479 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6480 return WINED3DERR_INVALIDCALL;
6484 if (This->onscreen_depth_stencil)
6486 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6487 This->onscreen_depth_stencil = NULL;
6490 /* Reset the depth stencil */
6491 if (pPresentationParameters->EnableAutoDepthStencil)
6492 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6493 else
6494 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6496 TRACE("Resetting stateblock\n");
6497 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6498 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6500 delete_opengl_contexts(iface, swapchain);
6502 if(pPresentationParameters->Windowed) {
6503 mode.Width = swapchain->orig_width;
6504 mode.Height = swapchain->orig_height;
6505 mode.RefreshRate = 0;
6506 mode.Format = swapchain->presentParms.BackBufferFormat;
6507 } else {
6508 mode.Width = pPresentationParameters->BackBufferWidth;
6509 mode.Height = pPresentationParameters->BackBufferHeight;
6510 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6511 mode.Format = swapchain->presentParms.BackBufferFormat;
6514 /* Should Width == 800 && Height == 0 set 800x600? */
6515 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6516 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6517 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6519 UINT i;
6521 if(!pPresentationParameters->Windowed) {
6522 DisplayModeChanged = TRUE;
6524 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6525 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6527 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6528 if(FAILED(hr))
6530 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6531 return hr;
6534 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6536 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6537 if(FAILED(hr))
6539 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6540 return hr;
6543 if (This->auto_depth_stencil)
6545 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6546 if(FAILED(hr))
6548 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6549 return hr;
6554 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6555 || DisplayModeChanged)
6557 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6559 if (!pPresentationParameters->Windowed)
6561 if(swapchain->presentParms.Windowed) {
6562 /* switch from windowed to fs */
6563 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6564 pPresentationParameters->BackBufferHeight);
6565 } else {
6566 /* Fullscreen -> fullscreen mode change */
6567 MoveWindow(swapchain->device_window, 0, 0,
6568 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6569 TRUE);
6572 else if (!swapchain->presentParms.Windowed)
6574 /* Fullscreen -> windowed switch */
6575 swapchain_restore_fullscreen_window(swapchain);
6577 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6578 } else if(!pPresentationParameters->Windowed) {
6579 DWORD style = This->style, exStyle = This->exStyle;
6580 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6581 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6582 * Reset to clear up their mess. Guild Wars also loses the device during that.
6584 This->style = 0;
6585 This->exStyle = 0;
6586 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6587 pPresentationParameters->BackBufferHeight);
6588 This->style = style;
6589 This->exStyle = exStyle;
6592 /* Note: No parent needed for initial internal stateblock */
6593 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6594 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6595 else TRACE("Created stateblock %p\n", This->stateBlock);
6596 This->updateStateBlock = This->stateBlock;
6597 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6599 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6600 if(FAILED(hr)) {
6601 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6604 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6606 RECT client_rect;
6607 GetClientRect(swapchain->win_handle, &client_rect);
6609 if(!swapchain->presentParms.BackBufferCount)
6611 TRACE("Single buffered rendering\n");
6612 swapchain->render_to_fbo = FALSE;
6614 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6615 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6617 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6618 swapchain->presentParms.BackBufferWidth,
6619 swapchain->presentParms.BackBufferHeight,
6620 client_rect.right, client_rect.bottom);
6621 swapchain->render_to_fbo = TRUE;
6623 else
6625 TRACE("Rendering directly to GL_BACK\n");
6626 swapchain->render_to_fbo = FALSE;
6630 hr = create_primary_opengl_context(iface, swapchain);
6631 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6633 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6634 * first use
6636 return hr;
6639 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6641 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6643 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6645 return WINED3D_OK;
6649 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6651 TRACE("(%p) : pParameters %p\n", This, pParameters);
6653 *pParameters = This->createParms;
6654 return WINED3D_OK;
6657 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6658 IWineD3DSwapChain *swapchain;
6660 TRACE("Relaying to swapchain\n");
6662 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6663 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6664 IWineD3DSwapChain_Release(swapchain);
6668 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6669 IWineD3DSwapChain *swapchain;
6671 TRACE("Relaying to swapchain\n");
6673 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6674 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6675 IWineD3DSwapChain_Release(swapchain);
6680 /** ********************************************************
6681 * Notification functions
6682 ** ********************************************************/
6683 /** This function must be called in the release of a resource when ref == 0,
6684 * the contents of resource must still be correct,
6685 * any handles to other resource held by the caller must be closed
6686 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6687 *****************************************************/
6688 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6690 TRACE("(%p) : Adding resource %p\n", This, resource);
6692 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6695 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6697 TRACE("(%p) : Removing resource %p\n", This, resource);
6699 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6702 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6704 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6705 int counter;
6707 TRACE("(%p) : resource %p\n", This, resource);
6709 context_resource_released((IWineD3DDevice *)This, resource, type);
6711 switch (type) {
6712 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6713 case WINED3DRTYPE_SURFACE: {
6714 unsigned int i;
6716 if (This->d3d_initialized)
6718 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6720 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6721 This->render_targets[i] = NULL;
6723 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6724 This->depth_stencil = NULL;
6727 break;
6729 case WINED3DRTYPE_TEXTURE:
6730 case WINED3DRTYPE_CUBETEXTURE:
6731 case WINED3DRTYPE_VOLUMETEXTURE:
6732 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6733 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6734 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6735 This->stateBlock->textures[counter] = NULL;
6737 if (This->updateStateBlock != This->stateBlock ){
6738 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6739 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6740 This->updateStateBlock->textures[counter] = NULL;
6744 break;
6745 case WINED3DRTYPE_VOLUME:
6746 /* TODO: nothing really? */
6747 break;
6748 case WINED3DRTYPE_BUFFER:
6750 int streamNumber;
6751 TRACE("Cleaning up stream pointers\n");
6753 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6754 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6755 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6757 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6758 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6759 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6760 This->updateStateBlock->streamSource[streamNumber] = 0;
6761 /* Set changed flag? */
6764 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) */
6765 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6766 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6767 This->stateBlock->streamSource[streamNumber] = 0;
6772 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6773 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6774 This->updateStateBlock->pIndexData = NULL;
6777 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6778 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6779 This->stateBlock->pIndexData = NULL;
6783 break;
6785 default:
6786 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6787 break;
6791 /* Remove the resource from the resourceStore */
6792 device_resource_remove(This, resource);
6794 TRACE("Resource released\n");
6798 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6800 IWineD3DResourceImpl *resource, *cursor;
6801 HRESULT ret;
6802 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6804 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6805 TRACE("enumerating resource %p\n", resource);
6806 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6807 ret = pCallback((IWineD3DResource *) resource, pData);
6808 if(ret == S_FALSE) {
6809 TRACE("Canceling enumeration\n");
6810 break;
6813 return WINED3D_OK;
6816 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6819 IWineD3DResourceImpl *resource;
6821 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6823 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6824 if (type == WINED3DRTYPE_SURFACE)
6826 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6828 TRACE("Found surface %p for dc %p.\n", resource, dc);
6829 *surface = (IWineD3DSurface *)resource;
6830 return WINED3D_OK;
6835 return WINED3DERR_INVALIDCALL;
6838 /**********************************************************
6839 * IWineD3DDevice VTbl follows
6840 **********************************************************/
6842 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6844 /*** IUnknown methods ***/
6845 IWineD3DDeviceImpl_QueryInterface,
6846 IWineD3DDeviceImpl_AddRef,
6847 IWineD3DDeviceImpl_Release,
6848 /*** IWineD3DDevice methods ***/
6849 IWineD3DDeviceImpl_GetParent,
6850 /*** Creation methods**/
6851 IWineD3DDeviceImpl_CreateBuffer,
6852 IWineD3DDeviceImpl_CreateVertexBuffer,
6853 IWineD3DDeviceImpl_CreateIndexBuffer,
6854 IWineD3DDeviceImpl_CreateStateBlock,
6855 IWineD3DDeviceImpl_CreateSurface,
6856 IWineD3DDeviceImpl_CreateRendertargetView,
6857 IWineD3DDeviceImpl_CreateTexture,
6858 IWineD3DDeviceImpl_CreateVolumeTexture,
6859 IWineD3DDeviceImpl_CreateVolume,
6860 IWineD3DDeviceImpl_CreateCubeTexture,
6861 IWineD3DDeviceImpl_CreateQuery,
6862 IWineD3DDeviceImpl_CreateSwapChain,
6863 IWineD3DDeviceImpl_CreateVertexDeclaration,
6864 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6865 IWineD3DDeviceImpl_CreateVertexShader,
6866 IWineD3DDeviceImpl_CreateGeometryShader,
6867 IWineD3DDeviceImpl_CreatePixelShader,
6868 IWineD3DDeviceImpl_CreatePalette,
6869 /*** Odd functions **/
6870 IWineD3DDeviceImpl_Init3D,
6871 IWineD3DDeviceImpl_InitGDI,
6872 IWineD3DDeviceImpl_Uninit3D,
6873 IWineD3DDeviceImpl_UninitGDI,
6874 IWineD3DDeviceImpl_SetMultithreaded,
6875 IWineD3DDeviceImpl_EvictManagedResources,
6876 IWineD3DDeviceImpl_GetAvailableTextureMem,
6877 IWineD3DDeviceImpl_GetBackBuffer,
6878 IWineD3DDeviceImpl_GetCreationParameters,
6879 IWineD3DDeviceImpl_GetDeviceCaps,
6880 IWineD3DDeviceImpl_GetDirect3D,
6881 IWineD3DDeviceImpl_GetDisplayMode,
6882 IWineD3DDeviceImpl_SetDisplayMode,
6883 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6884 IWineD3DDeviceImpl_GetRasterStatus,
6885 IWineD3DDeviceImpl_GetSwapChain,
6886 IWineD3DDeviceImpl_Reset,
6887 IWineD3DDeviceImpl_SetDialogBoxMode,
6888 IWineD3DDeviceImpl_SetCursorProperties,
6889 IWineD3DDeviceImpl_SetCursorPosition,
6890 IWineD3DDeviceImpl_ShowCursor,
6891 /*** Getters and setters **/
6892 IWineD3DDeviceImpl_SetClipPlane,
6893 IWineD3DDeviceImpl_GetClipPlane,
6894 IWineD3DDeviceImpl_SetClipStatus,
6895 IWineD3DDeviceImpl_GetClipStatus,
6896 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6897 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6898 IWineD3DDeviceImpl_SetDepthStencilSurface,
6899 IWineD3DDeviceImpl_GetDepthStencilSurface,
6900 IWineD3DDeviceImpl_SetGammaRamp,
6901 IWineD3DDeviceImpl_GetGammaRamp,
6902 IWineD3DDeviceImpl_SetIndexBuffer,
6903 IWineD3DDeviceImpl_GetIndexBuffer,
6904 IWineD3DDeviceImpl_SetBaseVertexIndex,
6905 IWineD3DDeviceImpl_GetBaseVertexIndex,
6906 IWineD3DDeviceImpl_SetLight,
6907 IWineD3DDeviceImpl_GetLight,
6908 IWineD3DDeviceImpl_SetLightEnable,
6909 IWineD3DDeviceImpl_GetLightEnable,
6910 IWineD3DDeviceImpl_SetMaterial,
6911 IWineD3DDeviceImpl_GetMaterial,
6912 IWineD3DDeviceImpl_SetNPatchMode,
6913 IWineD3DDeviceImpl_GetNPatchMode,
6914 IWineD3DDeviceImpl_SetPaletteEntries,
6915 IWineD3DDeviceImpl_GetPaletteEntries,
6916 IWineD3DDeviceImpl_SetPixelShader,
6917 IWineD3DDeviceImpl_GetPixelShader,
6918 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6919 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6920 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6921 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6922 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6923 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6924 IWineD3DDeviceImpl_SetRenderState,
6925 IWineD3DDeviceImpl_GetRenderState,
6926 IWineD3DDeviceImpl_SetRenderTarget,
6927 IWineD3DDeviceImpl_GetRenderTarget,
6928 IWineD3DDeviceImpl_SetFrontBackBuffers,
6929 IWineD3DDeviceImpl_SetSamplerState,
6930 IWineD3DDeviceImpl_GetSamplerState,
6931 IWineD3DDeviceImpl_SetScissorRect,
6932 IWineD3DDeviceImpl_GetScissorRect,
6933 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6934 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6935 IWineD3DDeviceImpl_SetStreamSource,
6936 IWineD3DDeviceImpl_GetStreamSource,
6937 IWineD3DDeviceImpl_SetStreamSourceFreq,
6938 IWineD3DDeviceImpl_GetStreamSourceFreq,
6939 IWineD3DDeviceImpl_SetTexture,
6940 IWineD3DDeviceImpl_GetTexture,
6941 IWineD3DDeviceImpl_SetTextureStageState,
6942 IWineD3DDeviceImpl_GetTextureStageState,
6943 IWineD3DDeviceImpl_SetTransform,
6944 IWineD3DDeviceImpl_GetTransform,
6945 IWineD3DDeviceImpl_SetVertexDeclaration,
6946 IWineD3DDeviceImpl_GetVertexDeclaration,
6947 IWineD3DDeviceImpl_SetVertexShader,
6948 IWineD3DDeviceImpl_GetVertexShader,
6949 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6950 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6951 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6952 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6953 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6954 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6955 IWineD3DDeviceImpl_SetViewport,
6956 IWineD3DDeviceImpl_GetViewport,
6957 IWineD3DDeviceImpl_MultiplyTransform,
6958 IWineD3DDeviceImpl_ValidateDevice,
6959 IWineD3DDeviceImpl_ProcessVertices,
6960 /*** State block ***/
6961 IWineD3DDeviceImpl_BeginStateBlock,
6962 IWineD3DDeviceImpl_EndStateBlock,
6963 /*** Scene management ***/
6964 IWineD3DDeviceImpl_BeginScene,
6965 IWineD3DDeviceImpl_EndScene,
6966 IWineD3DDeviceImpl_Present,
6967 IWineD3DDeviceImpl_Clear,
6968 IWineD3DDeviceImpl_ClearRendertargetView,
6969 /*** Drawing ***/
6970 IWineD3DDeviceImpl_SetPrimitiveType,
6971 IWineD3DDeviceImpl_GetPrimitiveType,
6972 IWineD3DDeviceImpl_DrawPrimitive,
6973 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6974 IWineD3DDeviceImpl_DrawPrimitiveUP,
6975 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6976 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6977 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6978 IWineD3DDeviceImpl_DrawRectPatch,
6979 IWineD3DDeviceImpl_DrawTriPatch,
6980 IWineD3DDeviceImpl_DeletePatch,
6981 IWineD3DDeviceImpl_ColorFill,
6982 IWineD3DDeviceImpl_UpdateTexture,
6983 IWineD3DDeviceImpl_UpdateSurface,
6984 IWineD3DDeviceImpl_GetFrontBufferData,
6985 /*** object tracking ***/
6986 IWineD3DDeviceImpl_EnumResources,
6987 IWineD3DDeviceImpl_GetSurfaceFromDC,
6988 IWineD3DDeviceImpl_AcquireFocusWindow,
6989 IWineD3DDeviceImpl_ReleaseFocusWindow,
6992 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6993 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6994 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6996 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6997 const struct fragment_pipeline *fragment_pipeline;
6998 struct shader_caps shader_caps;
6999 struct fragment_caps ffp_caps;
7000 WINED3DDISPLAYMODE mode;
7001 unsigned int i;
7002 HRESULT hr;
7004 device->lpVtbl = &IWineD3DDevice_Vtbl;
7005 device->ref = 1;
7006 device->wined3d = (IWineD3D *)wined3d;
7007 IWineD3D_AddRef(device->wined3d);
7008 device->adapter = wined3d->adapter_count ? adapter : NULL;
7009 device->parent = parent;
7010 device->device_parent = device_parent;
7011 list_init(&device->resources);
7012 list_init(&device->shaders);
7014 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7015 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7017 /* Get the initial screen setup for ddraw. */
7018 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7019 if (FAILED(hr))
7021 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7022 IWineD3D_Release(device->wined3d);
7023 return hr;
7025 device->ddraw_width = mode.Width;
7026 device->ddraw_height = mode.Height;
7027 device->ddraw_format = mode.Format;
7029 /* Save the creation parameters. */
7030 device->createParms.AdapterOrdinal = adapter_idx;
7031 device->createParms.DeviceType = device_type;
7032 device->createParms.hFocusWindow = focus_window;
7033 device->createParms.BehaviorFlags = flags;
7035 device->devType = device_type;
7036 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7038 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7039 device->shader_backend = adapter->shader_backend;
7041 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7042 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7043 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7044 device->vs_clipping = shader_caps.VSClipping;
7046 fragment_pipeline = adapter->fragment_pipe;
7047 device->frag_pipe = fragment_pipeline;
7048 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7049 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7051 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7052 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7053 if (FAILED(hr))
7055 ERR("Failed to compile state table, hr %#x.\n", hr);
7056 IWineD3D_Release(device->wined3d);
7057 return hr;
7060 device->blitter = adapter->blitter;
7062 return WINED3D_OK;
7066 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7067 DWORD rep = This->StateTable[state].representative;
7068 struct wined3d_context *context;
7069 DWORD idx;
7070 BYTE shift;
7071 UINT i;
7073 for(i = 0; i < This->numContexts; i++) {
7074 context = This->contexts[i];
7075 if(isStateDirty(context, rep)) continue;
7077 context->dirtyArray[context->numDirtyEntries++] = rep;
7078 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7079 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7080 context->isStateDirty[idx] |= (1 << shift);
7084 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7086 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7087 *width = context->current_rt->pow2Width;
7088 *height = context->current_rt->pow2Height;
7091 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7093 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7094 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7095 * current context's drawable, which is the size of the back buffer of the swapchain
7096 * the active context belongs to. */
7097 *width = swapchain->presentParms.BackBufferWidth;
7098 *height = swapchain->presentParms.BackBufferHeight;
7101 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7102 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7104 if (device->filter_messages)
7106 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7107 window, message, wparam, lparam);
7108 return DefWindowProcW(window, message, wparam, lparam);
7111 if (message == WM_DESTROY)
7113 TRACE("unregister window %p.\n", window);
7114 wined3d_unregister_window(window);
7116 if (device->focus_window == window) device->focus_window = NULL;
7117 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7120 return CallWindowProcW(proc, window, message, wparam, lparam);