wined3d: Use BltFast in UpdateSurface when desc.convert is set.
[wine/wine-gecko.git] / dlls / wined3d / device.c
blobfeb39499cb55902249e244c143d44c0700dc97e6
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);
4486 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)depth_stencil, SFLAG_INDRAWABLE, TRUE);
4488 glDepthMask(GL_TRUE);
4489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4490 glClearDepth(Z);
4491 checkGLcall("glClearDepth");
4492 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4495 if (Flags & WINED3DCLEAR_TARGET)
4497 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4499 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4504 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4505 checkGLcall("glClearColor");
4506 glMask = glMask | GL_COLOR_BUFFER_BIT;
4509 if (!clear_rect)
4511 if (context->render_offscreen)
4513 glScissor(draw_rect.left, draw_rect.top,
4514 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4516 else
4518 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
4519 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4521 checkGLcall("glScissor");
4522 glClear(glMask);
4523 checkGLcall("glClear");
4525 else
4527 RECT current_rect;
4529 /* Now process each rect in turn. */
4530 for (i = 0; i < Count; ++i)
4532 /* Note gl uses lower left, width/height */
4533 IntersectRect(&current_rect, &draw_rect, &clear_rect[i]);
4535 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
4536 wine_dbgstr_rect(&clear_rect[i]),
4537 wine_dbgstr_rect(&current_rect));
4539 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4540 * The rectangle is not cleared, no error is returned, but further rectanlges are
4541 * still cleared if they are valid. */
4542 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
4544 TRACE("Rectangle with negative dimensions, ignoring.\n");
4545 continue;
4548 if (context->render_offscreen)
4550 glScissor(current_rect.left, current_rect.top,
4551 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4553 else
4555 glScissor(current_rect.left, drawable_height - current_rect.bottom,
4556 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4558 checkGLcall("glScissor");
4560 glClear(glMask);
4561 checkGLcall("glClear");
4565 LEAVE_GL();
4567 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4568 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4569 wglFlush(); /* Flush to ensure ordering across contexts. */
4571 context_release(context);
4573 return WINED3D_OK;
4576 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4577 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4582 Count, pRects, Flags, Color, Z, Stencil);
4584 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4586 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4587 /* TODO: What about depth stencil buffers without stencil bits? */
4588 return WINED3DERR_INVALIDCALL;
4591 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4594 /*****
4595 * Drawing functions
4596 *****/
4598 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4599 WINED3DPRIMITIVETYPE primitive_type)
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4605 This->updateStateBlock->changed.primitive_type = TRUE;
4606 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4609 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4610 WINED3DPRIMITIVETYPE *primitive_type)
4612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4614 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4616 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4618 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4621 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4627 if(!This->stateBlock->vertexDecl) {
4628 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4629 return WINED3DERR_INVALIDCALL;
4632 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4633 if(This->stateBlock->streamIsUP) {
4634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4635 This->stateBlock->streamIsUP = FALSE;
4638 if(This->stateBlock->loadBaseVertexIndex != 0) {
4639 This->stateBlock->loadBaseVertexIndex = 0;
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4642 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4643 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4644 return WINED3D_OK;
4647 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 UINT idxStride = 2;
4651 IWineD3DBuffer *pIB;
4652 GLuint vbo;
4654 pIB = This->stateBlock->pIndexData;
4655 if (!pIB) {
4656 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4657 * without an index buffer set. (The first time at least...)
4658 * D3D8 simply dies, but I doubt it can do much harm to return
4659 * D3DERR_INVALIDCALL there as well. */
4660 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4661 return WINED3DERR_INVALIDCALL;
4664 if(!This->stateBlock->vertexDecl) {
4665 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4666 return WINED3DERR_INVALIDCALL;
4669 if(This->stateBlock->streamIsUP) {
4670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4671 This->stateBlock->streamIsUP = FALSE;
4673 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4675 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4677 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4678 idxStride = 2;
4679 } else {
4680 idxStride = 4;
4683 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4684 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4688 drawPrimitive(iface, index_count, startIndex, idxStride,
4689 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4691 return WINED3D_OK;
4694 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4695 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4698 IWineD3DBuffer *vb;
4700 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4701 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4703 if(!This->stateBlock->vertexDecl) {
4704 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4705 return WINED3DERR_INVALIDCALL;
4708 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4709 vb = This->stateBlock->streamSource[0];
4710 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4711 if (vb) IWineD3DBuffer_Release(vb);
4712 This->stateBlock->streamOffset[0] = 0;
4713 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4714 This->stateBlock->streamIsUP = TRUE;
4715 This->stateBlock->loadBaseVertexIndex = 0;
4717 /* TODO: Only mark dirty if drawing from a different UP address */
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4720 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4722 /* MSDN specifies stream zero settings must be set to NULL */
4723 This->stateBlock->streamStride[0] = 0;
4724 This->stateBlock->streamSource[0] = NULL;
4726 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4727 * the new stream sources or use UP drawing again
4729 return WINED3D_OK;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4733 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4734 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4736 int idxStride;
4737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4738 IWineD3DBuffer *vb;
4739 IWineD3DBuffer *ib;
4741 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4742 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4744 if(!This->stateBlock->vertexDecl) {
4745 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4746 return WINED3DERR_INVALIDCALL;
4749 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4750 idxStride = 2;
4751 } else {
4752 idxStride = 4;
4755 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4756 vb = This->stateBlock->streamSource[0];
4757 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4758 if (vb) IWineD3DBuffer_Release(vb);
4759 This->stateBlock->streamIsUP = TRUE;
4760 This->stateBlock->streamOffset[0] = 0;
4761 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4763 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4764 This->stateBlock->baseVertexIndex = 0;
4765 This->stateBlock->loadBaseVertexIndex = 0;
4766 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4770 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4772 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4773 This->stateBlock->streamSource[0] = NULL;
4774 This->stateBlock->streamStride[0] = 0;
4775 ib = This->stateBlock->pIndexData;
4776 if(ib) {
4777 IWineD3DBuffer_Release(ib);
4778 This->stateBlock->pIndexData = NULL;
4780 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4781 * SetStreamSource to specify a vertex buffer
4784 return WINED3D_OK;
4787 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4788 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4792 /* Mark the state dirty until we have nicer tracking
4793 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4794 * that value.
4796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4798 This->stateBlock->baseVertexIndex = 0;
4799 This->up_strided = DrawPrimStrideData;
4800 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4801 This->up_strided = NULL;
4802 return WINED3D_OK;
4805 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4806 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4807 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4810 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4812 /* Mark the state dirty until we have nicer tracking
4813 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4814 * that value.
4816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4817 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4818 This->stateBlock->streamIsUP = TRUE;
4819 This->stateBlock->baseVertexIndex = 0;
4820 This->up_strided = DrawPrimStrideData;
4821 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4822 This->up_strided = NULL;
4823 return WINED3D_OK;
4826 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4827 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4828 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4830 WINED3DLOCKED_BOX src;
4831 WINED3DLOCKED_BOX dst;
4832 HRESULT hr;
4834 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4835 iface, pSourceVolume, pDestinationVolume);
4837 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4838 * dirtification to improve loading performance.
4840 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4841 if(FAILED(hr)) return hr;
4842 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4843 if(FAILED(hr)) {
4844 IWineD3DVolume_UnlockBox(pSourceVolume);
4845 return hr;
4848 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4850 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4851 if(FAILED(hr)) {
4852 IWineD3DVolume_UnlockBox(pSourceVolume);
4853 } else {
4854 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4856 return hr;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4860 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4862 unsigned int level_count, i;
4863 WINED3DRESOURCETYPE type;
4864 HRESULT hr;
4866 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4868 /* Verify that the source and destination textures are non-NULL. */
4869 if (!src_texture || !dst_texture)
4871 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4872 return WINED3DERR_INVALIDCALL;
4875 if (src_texture == dst_texture)
4877 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4878 return WINED3DERR_INVALIDCALL;
4881 /* Verify that the source and destination textures are the same type. */
4882 type = IWineD3DBaseTexture_GetType(src_texture);
4883 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4885 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4886 return WINED3DERR_INVALIDCALL;
4889 /* Check that both textures have the identical numbers of levels. */
4890 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4891 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4893 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4894 return WINED3DERR_INVALIDCALL;
4897 /* Make sure that the destination texture is loaded. */
4898 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4900 /* Update every surface level of the texture. */
4901 switch (type)
4903 case WINED3DRTYPE_TEXTURE:
4905 IWineD3DSurface *src_surface;
4906 IWineD3DSurface *dst_surface;
4908 for (i = 0; i < level_count; ++i)
4910 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4911 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4912 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4913 IWineD3DSurface_Release(dst_surface);
4914 IWineD3DSurface_Release(src_surface);
4915 if (FAILED(hr))
4917 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4918 return hr;
4921 break;
4924 case WINED3DRTYPE_CUBETEXTURE:
4926 IWineD3DSurface *src_surface;
4927 IWineD3DSurface *dst_surface;
4928 WINED3DCUBEMAP_FACES face;
4930 for (i = 0; i < level_count; ++i)
4932 /* Update each cube face. */
4933 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4935 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4936 face, i, &src_surface);
4937 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4938 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4939 face, i, &dst_surface);
4940 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4941 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4942 IWineD3DSurface_Release(dst_surface);
4943 IWineD3DSurface_Release(src_surface);
4944 if (FAILED(hr))
4946 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4947 return hr;
4951 break;
4954 case WINED3DRTYPE_VOLUMETEXTURE:
4956 IWineD3DVolume *src_volume;
4957 IWineD3DVolume *dst_volume;
4959 for (i = 0; i < level_count; ++i)
4961 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4962 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4963 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4964 IWineD3DVolume_Release(dst_volume);
4965 IWineD3DVolume_Release(src_volume);
4966 if (FAILED(hr))
4968 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4969 return hr;
4972 break;
4975 default:
4976 FIXME("Unsupported texture type %#x.\n", type);
4977 return WINED3DERR_INVALIDCALL;
4980 return WINED3D_OK;
4983 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4984 IWineD3DSwapChain *swapChain;
4985 HRESULT hr;
4986 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4987 if(hr == WINED3D_OK) {
4988 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4989 IWineD3DSwapChain_Release(swapChain);
4991 return hr;
4994 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4996 IWineD3DBaseTextureImpl *texture;
4997 DWORD i;
4999 TRACE("(%p) : %p\n", This, pNumPasses);
5001 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5002 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5003 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5004 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5006 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5007 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5008 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5011 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5012 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5014 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5015 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5016 return E_FAIL;
5018 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5019 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5020 return E_FAIL;
5022 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5023 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5024 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5025 return E_FAIL;
5029 /* return a sensible default */
5030 *pNumPasses = 1;
5032 TRACE("returning D3D_OK\n");
5033 return WINED3D_OK;
5036 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5038 int i;
5040 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5042 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5043 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5044 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5046 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5051 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 int j;
5054 UINT NewSize;
5055 PALETTEENTRY **palettes;
5057 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5059 if (PaletteNumber >= MAX_PALETTES) {
5060 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5061 return WINED3DERR_INVALIDCALL;
5064 if (PaletteNumber >= This->NumberOfPalettes) {
5065 NewSize = This->NumberOfPalettes;
5066 do {
5067 NewSize *= 2;
5068 } while(PaletteNumber >= NewSize);
5069 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5070 if (!palettes) {
5071 ERR("Out of memory!\n");
5072 return E_OUTOFMEMORY;
5074 This->palettes = palettes;
5075 This->NumberOfPalettes = NewSize;
5078 if (!This->palettes[PaletteNumber]) {
5079 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5080 if (!This->palettes[PaletteNumber]) {
5081 ERR("Out of memory!\n");
5082 return E_OUTOFMEMORY;
5086 for (j = 0; j < 256; ++j) {
5087 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5088 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5089 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5090 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5092 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5093 TRACE("(%p) : returning\n", This);
5094 return WINED3D_OK;
5097 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5099 int j;
5100 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5101 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5102 /* What happens in such situation isn't documented; Native seems to silently abort
5103 on such conditions. Return Invalid Call. */
5104 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5105 return WINED3DERR_INVALIDCALL;
5107 for (j = 0; j < 256; ++j) {
5108 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5109 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5110 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5111 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5113 TRACE("(%p) : returning\n", This);
5114 return WINED3D_OK;
5117 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5120 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5121 (tested with reference rasterizer). Return Invalid Call. */
5122 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5123 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5124 return WINED3DERR_INVALIDCALL;
5126 /*TODO: stateblocks */
5127 if (This->currentPalette != PaletteNumber) {
5128 This->currentPalette = PaletteNumber;
5129 dirtify_p8_texture_samplers(This);
5131 TRACE("(%p) : returning\n", This);
5132 return WINED3D_OK;
5135 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 if (PaletteNumber == NULL) {
5138 WARN("(%p) : returning Invalid Call\n", This);
5139 return WINED3DERR_INVALIDCALL;
5141 /*TODO: stateblocks */
5142 *PaletteNumber = This->currentPalette;
5143 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5144 return WINED3D_OK;
5147 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 static BOOL warned;
5150 if (!warned)
5152 FIXME("(%p) : stub\n", This);
5153 warned = TRUE;
5156 This->softwareVertexProcessing = bSoftware;
5157 return WINED3D_OK;
5161 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 static BOOL warned;
5164 if (!warned)
5166 FIXME("(%p) : stub\n", This);
5167 warned = TRUE;
5169 return This->softwareVertexProcessing;
5172 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5173 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5175 IWineD3DSwapChain *swapchain;
5176 HRESULT hr;
5178 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5179 iface, swapchain_idx, raster_status);
5181 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5182 if (FAILED(hr))
5184 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5185 return hr;
5188 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5189 IWineD3DSwapChain_Release(swapchain);
5190 if (FAILED(hr))
5192 WARN("Failed to get raster status, hr %#x.\n", hr);
5193 return hr;
5196 return WINED3D_OK;
5199 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5201 static BOOL warned;
5202 if(nSegments != 0.0f) {
5203 if (!warned)
5205 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5206 warned = TRUE;
5209 return WINED3D_OK;
5212 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5214 static BOOL warned;
5215 if (!warned)
5217 FIXME("iface %p stub!\n", iface);
5218 warned = TRUE;
5220 return 0.0f;
5223 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5224 IWineD3DSurface *src_surface, const RECT *src_rect,
5225 IWineD3DSurface *dst_surface, const POINT *dst_point)
5227 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5228 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5230 const struct wined3d_format_desc *src_format;
5231 const struct wined3d_format_desc *dst_format;
5232 struct wined3d_context *context;
5233 const unsigned char *data;
5234 UINT update_w, update_h;
5235 CONVERT_TYPES convert;
5236 UINT src_w, src_h;
5237 UINT dst_x, dst_y;
5238 DWORD sampler;
5239 struct wined3d_format_desc desc;
5241 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5242 iface, src_surface, wine_dbgstr_rect(src_rect),
5243 dst_surface, wine_dbgstr_point(dst_point));
5245 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5247 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5248 src_surface, dst_surface);
5249 return WINED3DERR_INVALIDCALL;
5252 src_format = src_impl->resource.format_desc;
5253 dst_format = dst_impl->resource.format_desc;
5255 if (src_format->format != dst_format->format)
5257 WARN("Source and destination surfaces should have the same format.\n");
5258 return WINED3DERR_INVALIDCALL;
5261 dst_x = dst_point ? dst_point->x : 0;
5262 dst_y = dst_point ? dst_point->y : 0;
5264 /* This call loads the OpenGL surface directly, instead of copying the
5265 * surface to the destination's sysmem copy. If surface conversion is
5266 * needed, use BltFast instead to copy in sysmem and use regular surface
5267 * loading. */
5268 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5269 if (convert != NO_CONVERSION || desc.convert)
5270 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5272 context = context_acquire(This, NULL);
5274 ENTER_GL();
5275 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5276 checkGLcall("glActiveTextureARB");
5277 LEAVE_GL();
5279 /* Make sure the surface is loaded and up to date */
5280 surface_internal_preload(dst_impl, SRGB_RGB);
5281 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5283 src_w = src_impl->currentDesc.Width;
5284 src_h = src_impl->currentDesc.Height;
5285 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5286 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5288 data = IWineD3DSurface_GetData(src_surface);
5289 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5291 ENTER_GL();
5293 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5295 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5296 UINT row_count = update_h / src_format->block_height;
5297 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5299 if (src_rect)
5301 data += (src_rect->top / src_format->block_height) * src_pitch;
5302 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5305 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5306 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5307 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5309 if (row_length == src_pitch)
5311 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5312 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5314 else
5316 UINT row, y;
5318 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5319 * can't use the unpack row length like below. */
5320 for (row = 0, y = dst_y; row < row_count; ++row)
5322 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5323 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5324 y += src_format->block_height;
5325 data += src_pitch;
5328 checkGLcall("glCompressedTexSubImage2DARB");
5330 else
5332 if (src_rect)
5334 data += src_rect->top * src_w * src_format->byte_count;
5335 data += src_rect->left * src_format->byte_count;
5338 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5339 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5340 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5342 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5343 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5344 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5345 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5346 checkGLcall("glTexSubImage2D");
5349 LEAVE_GL();
5350 context_release(context);
5352 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5353 sampler = This->rev_tex_unit_map[0];
5354 if (sampler != WINED3D_UNMAPPED_STAGE)
5356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5359 return WINED3D_OK;
5362 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 struct WineD3DRectPatch *patch;
5365 GLenum old_primitive_type;
5366 unsigned int i;
5367 struct list *e;
5368 BOOL found;
5369 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5371 if(!(Handle || pRectPatchInfo)) {
5372 /* TODO: Write a test for the return value, thus the FIXME */
5373 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5374 return WINED3DERR_INVALIDCALL;
5377 if(Handle) {
5378 i = PATCHMAP_HASHFUNC(Handle);
5379 found = FALSE;
5380 LIST_FOR_EACH(e, &This->patches[i]) {
5381 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5382 if(patch->Handle == Handle) {
5383 found = TRUE;
5384 break;
5388 if(!found) {
5389 TRACE("Patch does not exist. Creating a new one\n");
5390 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5391 patch->Handle = Handle;
5392 list_add_head(&This->patches[i], &patch->entry);
5393 } else {
5394 TRACE("Found existing patch %p\n", patch);
5396 } else {
5397 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5398 * attributes we have to tesselate, read back, and draw. This needs a patch
5399 * management structure instance. Create one.
5401 * A possible improvement is to check if a vertex shader is used, and if not directly
5402 * draw the patch.
5404 FIXME("Drawing an uncached patch. This is slow\n");
5405 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5408 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5409 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5410 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5411 HRESULT hr;
5412 TRACE("Tesselation density or patch info changed, retesselating\n");
5414 if(pRectPatchInfo) {
5415 patch->RectPatchInfo = *pRectPatchInfo;
5417 patch->numSegs[0] = pNumSegs[0];
5418 patch->numSegs[1] = pNumSegs[1];
5419 patch->numSegs[2] = pNumSegs[2];
5420 patch->numSegs[3] = pNumSegs[3];
5422 hr = tesselate_rectpatch(This, patch);
5423 if(FAILED(hr)) {
5424 WARN("Patch tesselation failed\n");
5426 /* Do not release the handle to store the params of the patch */
5427 if(!Handle) {
5428 HeapFree(GetProcessHeap(), 0, patch);
5430 return hr;
5434 This->currentPatch = patch;
5435 old_primitive_type = This->stateBlock->gl_primitive_type;
5436 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5437 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5438 This->stateBlock->gl_primitive_type = old_primitive_type;
5439 This->currentPatch = NULL;
5441 /* Destroy uncached patches */
5442 if(!Handle) {
5443 HeapFree(GetProcessHeap(), 0, patch->mem);
5444 HeapFree(GetProcessHeap(), 0, patch);
5446 return WINED3D_OK;
5449 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5450 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5452 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5453 iface, handle, segment_count, patch_info);
5455 return WINED3D_OK;
5458 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5460 int i;
5461 struct WineD3DRectPatch *patch;
5462 struct list *e;
5463 TRACE("(%p) Handle(%d)\n", This, Handle);
5465 i = PATCHMAP_HASHFUNC(Handle);
5466 LIST_FOR_EACH(e, &This->patches[i]) {
5467 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5468 if(patch->Handle == Handle) {
5469 TRACE("Deleting patch %p\n", patch);
5470 list_remove(&patch->entry);
5471 HeapFree(GetProcessHeap(), 0, patch->mem);
5472 HeapFree(GetProcessHeap(), 0, patch);
5473 return WINED3D_OK;
5477 /* TODO: Write a test for the return value */
5478 FIXME("Attempt to destroy nonexistent patch\n");
5479 return WINED3DERR_INVALIDCALL;
5482 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5483 const WINED3DRECT *rect, const float color[4])
5485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5486 struct wined3d_context *context;
5488 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5489 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5491 context = context_acquire(This, surface);
5492 context_apply_clear_state(context, This, surface, NULL);
5494 ENTER_GL();
5496 if (rect)
5498 if (surface_is_offscreen(surface))
5499 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5500 else
5501 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5502 rect->x2 - rect->x1, rect->y2 - rect->y1);
5503 checkGLcall("glScissor");
5505 else
5507 glDisable(GL_SCISSOR_TEST);
5510 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5516 glClearColor(color[0], color[1], color[2], color[3]);
5517 glClear(GL_COLOR_BUFFER_BIT);
5518 checkGLcall("glClear");
5520 LEAVE_GL();
5522 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5524 context_release(context);
5527 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5528 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5530 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5531 WINEDDBLTFX BltFx;
5533 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5535 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5536 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5537 return WINED3DERR_INVALIDCALL;
5540 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5541 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5542 color_fill_fbo(iface, surface, pRect, c);
5543 return WINED3D_OK;
5544 } else {
5545 /* Just forward this to the DirectDraw blitting engine */
5546 memset(&BltFx, 0, sizeof(BltFx));
5547 BltFx.dwSize = sizeof(BltFx);
5548 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5549 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5550 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5554 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5555 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5557 IWineD3DResource *resource;
5558 IWineD3DSurfaceImpl *surface;
5559 HRESULT hr;
5561 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5562 if (FAILED(hr))
5564 ERR("Failed to get resource, hr %#x\n", hr);
5565 return;
5568 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5570 FIXME("Only supported on surface resources\n");
5571 IWineD3DResource_Release(resource);
5572 return;
5575 surface = (IWineD3DSurfaceImpl *)resource;
5577 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5579 color_fill_fbo(iface, surface, NULL, color);
5581 else
5583 WINEDDBLTFX BltFx;
5584 WINED3DCOLOR c;
5586 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5588 c = ((DWORD)(color[2] * 255.0f));
5589 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5590 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5591 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5593 /* Just forward this to the DirectDraw blitting engine */
5594 memset(&BltFx, 0, sizeof(BltFx));
5595 BltFx.dwSize = sizeof(BltFx);
5596 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5597 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5598 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5599 if (FAILED(hr))
5601 ERR("Blt failed, hr %#x\n", hr);
5605 IWineD3DResource_Release(resource);
5608 /* rendertarget and depth stencil functions */
5609 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5614 ERR("(%p) : Only %d render targets are supported.\n",
5615 This, This->adapter->gl_info.limits.buffers);
5616 return WINED3DERR_INVALIDCALL;
5619 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5620 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5621 /* Note inc ref on returned surface */
5622 if(*ppRenderTarget != NULL)
5623 IWineD3DSurface_AddRef(*ppRenderTarget);
5624 return WINED3D_OK;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5628 IWineD3DSurface *front, IWineD3DSurface *back)
5630 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5631 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5632 IWineD3DSwapChainImpl *swapchain;
5633 HRESULT hr;
5635 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5637 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5639 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5640 return hr;
5643 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5645 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5646 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5647 return WINED3DERR_INVALIDCALL;
5650 if (back_impl)
5652 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5654 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5655 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5656 return WINED3DERR_INVALIDCALL;
5659 if (!swapchain->back_buffers)
5661 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5662 if (!swapchain->back_buffers)
5664 ERR("Failed to allocate back buffer array memory.\n");
5665 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5666 return E_OUTOFMEMORY;
5671 if (swapchain->front_buffer != front_impl)
5673 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5675 if (swapchain->front_buffer)
5677 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5678 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5680 swapchain->front_buffer = front_impl;
5682 if (front)
5684 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5685 front_impl->Flags |= SFLAG_SWAPCHAIN;
5689 if (swapchain->back_buffers[0] != back_impl)
5691 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5693 if (swapchain->back_buffers[0])
5695 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5696 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5698 swapchain->back_buffers[0] = back_impl;
5700 if (back)
5702 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5703 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5704 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5705 swapchain->presentParms.BackBufferCount = 1;
5707 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5708 back_impl->Flags |= SFLAG_SWAPCHAIN;
5710 else
5712 swapchain->presentParms.BackBufferCount = 0;
5713 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5714 swapchain->back_buffers = NULL;
5718 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5719 return WINED3D_OK;
5722 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5725 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5727 if(*ppZStencilSurface != NULL) {
5728 /* Note inc ref on returned surface */
5729 IWineD3DSurface_AddRef(*ppZStencilSurface);
5730 return WINED3D_OK;
5731 } else {
5732 return WINED3DERR_NOTFOUND;
5736 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5737 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5739 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5740 const struct wined3d_gl_info *gl_info;
5741 struct wined3d_context *context;
5742 GLenum gl_filter;
5743 POINT offset = {0, 0};
5744 RECT src_rect, dst_rect;
5746 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5747 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5748 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5750 src_rect = *src_rect_in;
5751 dst_rect = *dst_rect_in;
5753 switch (filter) {
5754 case WINED3DTEXF_LINEAR:
5755 gl_filter = GL_LINEAR;
5756 break;
5758 default:
5759 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5760 case WINED3DTEXF_NONE:
5761 case WINED3DTEXF_POINT:
5762 gl_filter = GL_NEAREST;
5763 break;
5766 /* Make sure the drawables are up-to-date. Note that loading the
5767 * destination surface isn't strictly required if we overwrite the
5768 * entire surface. */
5769 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5770 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5772 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface);
5773 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface);
5774 else context = context_acquire(device, NULL);
5776 if (!context->valid)
5778 context_release(context);
5779 WARN("Invalid context, skipping blit.\n");
5780 return;
5783 gl_info = context->gl_info;
5785 if (!surface_is_offscreen(src_surface))
5787 GLenum buffer = surface_get_gl_buffer(src_surface);
5789 TRACE("Source surface %p is onscreen\n", src_surface);
5791 if(buffer == GL_FRONT) {
5792 RECT windowsize;
5793 UINT h;
5794 ClientToScreen(context->win_handle, &offset);
5795 GetClientRect(context->win_handle, &windowsize);
5796 h = windowsize.bottom - windowsize.top;
5797 src_rect.left -= offset.x; src_rect.right -=offset.x;
5798 src_rect.top = offset.y + h - src_rect.top;
5799 src_rect.bottom = offset.y + h - src_rect.bottom;
5800 } else {
5801 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5802 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5805 ENTER_GL();
5806 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5807 glReadBuffer(buffer);
5808 checkGLcall("glReadBuffer()");
5809 } else {
5810 TRACE("Source surface %p is offscreen\n", src_surface);
5811 ENTER_GL();
5812 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL);
5813 glReadBuffer(GL_COLOR_ATTACHMENT0);
5814 checkGLcall("glReadBuffer()");
5816 LEAVE_GL();
5818 /* Attach dst surface to dst fbo */
5819 if (!surface_is_offscreen(dst_surface))
5821 GLenum buffer = surface_get_gl_buffer(dst_surface);
5823 TRACE("Destination surface %p is onscreen\n", dst_surface);
5825 if(buffer == GL_FRONT) {
5826 RECT windowsize;
5827 UINT h;
5828 ClientToScreen(context->win_handle, &offset);
5829 GetClientRect(context->win_handle, &windowsize);
5830 h = windowsize.bottom - windowsize.top;
5831 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5832 dst_rect.top = offset.y + h - dst_rect.top;
5833 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5834 } else {
5835 /* Screen coords = window coords, surface height = window height */
5836 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5837 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5840 ENTER_GL();
5841 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5842 context_set_draw_buffer(context, buffer);
5844 else
5846 TRACE("Destination surface %p is offscreen\n", dst_surface);
5848 ENTER_GL();
5849 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL);
5850 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5852 glDisable(GL_SCISSOR_TEST);
5853 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5855 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5856 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5857 checkGLcall("glBlitFramebuffer()");
5859 LEAVE_GL();
5861 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5863 context_release(context);
5865 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5868 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5869 BOOL set_viewport) {
5870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5872 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5874 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5876 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5877 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5878 return WINED3DERR_INVALIDCALL;
5881 /* MSDN says that null disables the render target
5882 but a device must always be associated with a render target
5883 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5885 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5886 FIXME("Trying to set render target 0 to NULL\n");
5887 return WINED3DERR_INVALIDCALL;
5889 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5890 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);
5891 return WINED3DERR_INVALIDCALL;
5894 /* If we are trying to set what we already have, don't bother */
5895 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5897 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5898 return WINED3D_OK;
5900 if (pRenderTarget)
5901 IWineD3DSurface_AddRef(pRenderTarget);
5902 if (This->render_targets[RenderTargetIndex])
5903 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5904 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5906 /* Render target 0 is special */
5907 if(RenderTargetIndex == 0 && set_viewport) {
5908 /* Finally, reset the viewport and scissor rect as the MSDN states.
5909 * Tests show that stateblock recording is ignored, the change goes
5910 * directly into the primary stateblock.
5912 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5913 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5914 This->stateBlock->viewport.X = 0;
5915 This->stateBlock->viewport.Y = 0;
5916 This->stateBlock->viewport.MaxZ = 1.0f;
5917 This->stateBlock->viewport.MinZ = 0.0f;
5918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5920 This->stateBlock->scissorRect.top = 0;
5921 This->stateBlock->scissorRect.left = 0;
5922 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5923 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5926 return WINED3D_OK;
5929 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5931 IWineD3DSurfaceImpl *tmp;
5933 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5935 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5937 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5938 return WINED3D_OK;
5941 if (This->depth_stencil)
5943 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5944 || This->depth_stencil->Flags & SFLAG_DISCARD)
5946 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5947 This->depth_stencil->currentDesc.Width,
5948 This->depth_stencil->currentDesc.Height);
5949 if (This->depth_stencil == This->onscreen_depth_stencil)
5951 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5952 This->onscreen_depth_stencil = NULL;
5957 tmp = This->depth_stencil;
5958 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5959 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5960 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5962 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5964 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5970 return WINED3D_OK;
5973 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5974 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5976 /* TODO: the use of Impl is deprecated. */
5977 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5978 WINED3DLOCKED_RECT lockedRect;
5980 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5982 /* some basic validation checks */
5983 if (This->cursorTexture)
5985 struct wined3d_context *context = context_acquire(This, NULL);
5986 ENTER_GL();
5987 glDeleteTextures(1, &This->cursorTexture);
5988 LEAVE_GL();
5989 context_release(context);
5990 This->cursorTexture = 0;
5993 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5994 This->haveHardwareCursor = TRUE;
5995 else
5996 This->haveHardwareCursor = FALSE;
5998 if(pCursorBitmap) {
5999 WINED3DLOCKED_RECT rect;
6001 /* MSDN: Cursor must be A8R8G8B8 */
6002 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6004 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6005 return WINED3DERR_INVALIDCALL;
6008 /* MSDN: Cursor must be smaller than the display mode */
6009 if(pSur->currentDesc.Width > This->ddraw_width ||
6010 pSur->currentDesc.Height > This->ddraw_height) {
6011 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);
6012 return WINED3DERR_INVALIDCALL;
6015 if (!This->haveHardwareCursor) {
6016 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6018 /* Do not store the surface's pointer because the application may
6019 * release it after setting the cursor image. Windows doesn't
6020 * addref the set surface, so we can't do this either without
6021 * creating circular refcount dependencies. Copy out the gl texture
6022 * instead.
6024 This->cursorWidth = pSur->currentDesc.Width;
6025 This->cursorHeight = pSur->currentDesc.Height;
6026 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6028 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6029 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6030 struct wined3d_context *context;
6031 char *mem, *bits = rect.pBits;
6032 GLint intfmt = format_desc->glInternal;
6033 GLint format = format_desc->glFormat;
6034 GLint type = format_desc->glType;
6035 INT height = This->cursorHeight;
6036 INT width = This->cursorWidth;
6037 INT bpp = format_desc->byte_count;
6038 DWORD sampler;
6039 INT i;
6041 /* Reformat the texture memory (pitch and width can be
6042 * different) */
6043 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6044 for(i = 0; i < height; i++)
6045 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6046 IWineD3DSurface_UnlockRect(pCursorBitmap);
6048 context = context_acquire(This, NULL);
6050 ENTER_GL();
6052 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6054 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6055 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6058 /* Make sure that a proper texture unit is selected */
6059 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6060 checkGLcall("glActiveTextureARB");
6061 sampler = This->rev_tex_unit_map[0];
6062 if (sampler != WINED3D_UNMAPPED_STAGE)
6064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6066 /* Create a new cursor texture */
6067 glGenTextures(1, &This->cursorTexture);
6068 checkGLcall("glGenTextures");
6069 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6070 checkGLcall("glBindTexture");
6071 /* Copy the bitmap memory into the cursor texture */
6072 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6073 HeapFree(GetProcessHeap(), 0, mem);
6074 checkGLcall("glTexImage2D");
6076 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6078 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6079 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6082 LEAVE_GL();
6084 context_release(context);
6086 else
6088 FIXME("A cursor texture was not returned.\n");
6089 This->cursorTexture = 0;
6092 else
6094 /* Draw a hardware cursor */
6095 ICONINFO cursorInfo;
6096 HCURSOR cursor;
6097 /* Create and clear maskBits because it is not needed for
6098 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6099 * chunks. */
6100 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6101 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6102 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6103 WINED3DLOCK_NO_DIRTY_UPDATE |
6104 WINED3DLOCK_READONLY
6106 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6107 pSur->currentDesc.Height);
6109 cursorInfo.fIcon = FALSE;
6110 cursorInfo.xHotspot = XHotSpot;
6111 cursorInfo.yHotspot = YHotSpot;
6112 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6113 1, 1, maskBits);
6114 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6115 1, 32, lockedRect.pBits);
6116 IWineD3DSurface_UnlockRect(pCursorBitmap);
6117 /* Create our cursor and clean up. */
6118 cursor = CreateIconIndirect(&cursorInfo);
6119 SetCursor(cursor);
6120 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6121 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6122 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6123 This->hardwareCursor = cursor;
6124 HeapFree(GetProcessHeap(), 0, maskBits);
6128 This->xHotSpot = XHotSpot;
6129 This->yHotSpot = YHotSpot;
6130 return WINED3D_OK;
6133 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6135 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6137 This->xScreenSpace = XScreenSpace;
6138 This->yScreenSpace = YScreenSpace;
6140 return;
6144 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6146 BOOL oldVisible = This->bCursorVisible;
6147 POINT pt;
6149 TRACE("(%p) : visible(%d)\n", This, bShow);
6152 * When ShowCursor is first called it should make the cursor appear at the OS's last
6153 * known cursor position. Because of this, some applications just repetitively call
6154 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6156 GetCursorPos(&pt);
6157 This->xScreenSpace = pt.x;
6158 This->yScreenSpace = pt.y;
6160 if (This->haveHardwareCursor) {
6161 This->bCursorVisible = bShow;
6162 if (bShow)
6163 SetCursor(This->hardwareCursor);
6164 else
6165 SetCursor(NULL);
6167 else
6169 if (This->cursorTexture)
6170 This->bCursorVisible = bShow;
6173 return oldVisible;
6176 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6177 TRACE("checking resource %p for eviction\n", resource);
6178 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6179 TRACE("Evicting %p\n", resource);
6180 IWineD3DResource_UnLoad(resource);
6182 IWineD3DResource_Release(resource);
6183 return S_OK;
6186 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6188 TRACE("iface %p.\n", iface);
6190 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6191 return WINED3D_OK;
6194 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6196 IWineD3DDeviceImpl *device = surface->resource.device;
6197 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6199 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6200 if(surface->Flags & SFLAG_DIBSECTION) {
6201 /* Release the DC */
6202 SelectObject(surface->hDC, surface->dib.holdbitmap);
6203 DeleteDC(surface->hDC);
6204 /* Release the DIB section */
6205 DeleteObject(surface->dib.DIBsection);
6206 surface->dib.bitmap_data = NULL;
6207 surface->resource.allocatedMemory = NULL;
6208 surface->Flags &= ~SFLAG_DIBSECTION;
6210 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6211 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6212 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6213 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6215 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6216 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6217 } else {
6218 surface->pow2Width = surface->pow2Height = 1;
6219 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6220 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6223 if (surface->texture_name)
6225 struct wined3d_context *context = context_acquire(device, NULL);
6226 ENTER_GL();
6227 glDeleteTextures(1, &surface->texture_name);
6228 LEAVE_GL();
6229 context_release(context);
6230 surface->texture_name = 0;
6231 surface->Flags &= ~SFLAG_CLIENT;
6233 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6234 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6235 surface->Flags |= SFLAG_NONPOW2;
6236 } else {
6237 surface->Flags &= ~SFLAG_NONPOW2;
6239 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6240 surface->resource.allocatedMemory = NULL;
6241 surface->resource.heapMemory = NULL;
6242 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6244 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6245 * to a FBO */
6246 if (!surface_init_sysmem(surface))
6248 return E_OUTOFMEMORY;
6250 return WINED3D_OK;
6253 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6254 TRACE("Unloading resource %p\n", resource);
6255 IWineD3DResource_UnLoad(resource);
6256 IWineD3DResource_Release(resource);
6257 return S_OK;
6260 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6262 UINT i, count;
6263 WINED3DDISPLAYMODE m;
6264 HRESULT hr;
6266 /* All Windowed modes are supported, as is leaving the current mode */
6267 if(pp->Windowed) return TRUE;
6268 if(!pp->BackBufferWidth) return TRUE;
6269 if(!pp->BackBufferHeight) return TRUE;
6271 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6272 for(i = 0; i < count; i++) {
6273 memset(&m, 0, sizeof(m));
6274 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6275 if(FAILED(hr)) {
6276 ERR("EnumAdapterModes failed\n");
6278 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6279 /* Mode found, it is supported */
6280 return TRUE;
6283 /* Mode not found -> not supported */
6284 return FALSE;
6287 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6290 const struct wined3d_gl_info *gl_info;
6291 struct wined3d_context *context;
6292 IWineD3DBaseShaderImpl *shader;
6294 context = context_acquire(This, NULL);
6295 gl_info = context->gl_info;
6297 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6298 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6299 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6302 ENTER_GL();
6303 if(This->depth_blt_texture) {
6304 glDeleteTextures(1, &This->depth_blt_texture);
6305 This->depth_blt_texture = 0;
6307 if (This->depth_blt_rb) {
6308 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6309 This->depth_blt_rb = 0;
6310 This->depth_blt_rb_w = 0;
6311 This->depth_blt_rb_h = 0;
6313 LEAVE_GL();
6315 This->blitter->free_private(iface);
6316 This->frag_pipe->free_private(iface);
6317 This->shader_backend->shader_free_private(iface);
6318 destroy_dummy_textures(This, gl_info);
6320 context_release(context);
6322 while (This->numContexts)
6324 context_destroy(This, This->contexts[0]);
6326 HeapFree(GetProcessHeap(), 0, swapchain->context);
6327 swapchain->context = NULL;
6328 swapchain->num_contexts = 0;
6331 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6334 struct wined3d_context *context;
6335 HRESULT hr;
6336 IWineD3DSurfaceImpl *target;
6338 /* Recreate the primary swapchain's context */
6339 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6340 if (!swapchain->context)
6342 ERR("Failed to allocate memory for swapchain context array.\n");
6343 return E_OUTOFMEMORY;
6346 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6347 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6349 WARN("Failed to create context.\n");
6350 HeapFree(GetProcessHeap(), 0, swapchain->context);
6351 return E_FAIL;
6354 swapchain->context[0] = context;
6355 swapchain->num_contexts = 1;
6356 create_dummy_textures(This);
6357 context_release(context);
6359 hr = This->shader_backend->shader_alloc_private(iface);
6360 if (FAILED(hr))
6362 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6363 goto err;
6366 hr = This->frag_pipe->alloc_private(iface);
6367 if (FAILED(hr))
6369 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6370 This->shader_backend->shader_free_private(iface);
6371 goto err;
6374 hr = This->blitter->alloc_private(iface);
6375 if (FAILED(hr))
6377 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6378 This->frag_pipe->free_private(iface);
6379 This->shader_backend->shader_free_private(iface);
6380 goto err;
6383 return WINED3D_OK;
6385 err:
6386 context_acquire(This, NULL);
6387 destroy_dummy_textures(This, context->gl_info);
6388 context_release(context);
6389 context_destroy(This, context);
6390 HeapFree(GetProcessHeap(), 0, swapchain->context);
6391 swapchain->num_contexts = 0;
6392 return hr;
6395 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6397 IWineD3DSwapChainImpl *swapchain;
6398 HRESULT hr;
6399 BOOL DisplayModeChanged = FALSE;
6400 WINED3DDISPLAYMODE mode;
6401 TRACE("(%p)\n", This);
6403 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6404 if(FAILED(hr)) {
6405 ERR("Failed to get the first implicit swapchain\n");
6406 return hr;
6409 if(!is_display_mode_supported(This, pPresentationParameters)) {
6410 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6411 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6412 pPresentationParameters->BackBufferHeight);
6413 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6414 return WINED3DERR_INVALIDCALL;
6417 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6418 * on an existing gl context, so there's no real need for recreation.
6420 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6422 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6424 TRACE("New params:\n");
6425 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6426 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6427 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6428 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6429 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6430 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6431 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6432 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6433 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6434 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6435 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6436 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6437 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6439 /* No special treatment of these parameters. Just store them */
6440 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6441 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6442 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6443 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6445 /* What to do about these? */
6446 if(pPresentationParameters->BackBufferCount != 0 &&
6447 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6448 ERR("Cannot change the back buffer count yet\n");
6450 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6451 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6452 ERR("Cannot change the back buffer format yet\n");
6454 if(pPresentationParameters->hDeviceWindow != NULL &&
6455 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6456 ERR("Cannot change the device window yet\n");
6458 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6460 HRESULT hrc;
6462 TRACE("Creating the depth stencil buffer\n");
6464 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6465 This->parent,
6466 pPresentationParameters->BackBufferWidth,
6467 pPresentationParameters->BackBufferHeight,
6468 pPresentationParameters->AutoDepthStencilFormat,
6469 pPresentationParameters->MultiSampleType,
6470 pPresentationParameters->MultiSampleQuality,
6471 FALSE,
6472 (IWineD3DSurface **)&This->auto_depth_stencil);
6474 if (FAILED(hrc)) {
6475 ERR("Failed to create the depth stencil buffer\n");
6476 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6477 return WINED3DERR_INVALIDCALL;
6481 if (This->onscreen_depth_stencil)
6483 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6484 This->onscreen_depth_stencil = NULL;
6487 /* Reset the depth stencil */
6488 if (pPresentationParameters->EnableAutoDepthStencil)
6489 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6490 else
6491 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6493 TRACE("Resetting stateblock\n");
6494 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6495 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6497 delete_opengl_contexts(iface, swapchain);
6499 if(pPresentationParameters->Windowed) {
6500 mode.Width = swapchain->orig_width;
6501 mode.Height = swapchain->orig_height;
6502 mode.RefreshRate = 0;
6503 mode.Format = swapchain->presentParms.BackBufferFormat;
6504 } else {
6505 mode.Width = pPresentationParameters->BackBufferWidth;
6506 mode.Height = pPresentationParameters->BackBufferHeight;
6507 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6508 mode.Format = swapchain->presentParms.BackBufferFormat;
6511 /* Should Width == 800 && Height == 0 set 800x600? */
6512 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6513 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6514 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6516 UINT i;
6518 if(!pPresentationParameters->Windowed) {
6519 DisplayModeChanged = TRUE;
6521 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6522 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6524 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6525 if(FAILED(hr))
6527 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6528 return hr;
6531 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6533 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6534 if(FAILED(hr))
6536 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6537 return hr;
6540 if (This->auto_depth_stencil)
6542 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6543 if(FAILED(hr))
6545 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6546 return hr;
6551 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6552 || DisplayModeChanged)
6554 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6556 if (!pPresentationParameters->Windowed)
6558 if(swapchain->presentParms.Windowed) {
6559 /* switch from windowed to fs */
6560 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6561 pPresentationParameters->BackBufferHeight);
6562 } else {
6563 /* Fullscreen -> fullscreen mode change */
6564 MoveWindow(swapchain->device_window, 0, 0,
6565 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6566 TRUE);
6569 else if (!swapchain->presentParms.Windowed)
6571 /* Fullscreen -> windowed switch */
6572 swapchain_restore_fullscreen_window(swapchain);
6574 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6575 } else if(!pPresentationParameters->Windowed) {
6576 DWORD style = This->style, exStyle = This->exStyle;
6577 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6578 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6579 * Reset to clear up their mess. Guild Wars also loses the device during that.
6581 This->style = 0;
6582 This->exStyle = 0;
6583 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6584 pPresentationParameters->BackBufferHeight);
6585 This->style = style;
6586 This->exStyle = exStyle;
6589 /* Note: No parent needed for initial internal stateblock */
6590 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6591 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6592 else TRACE("Created stateblock %p\n", This->stateBlock);
6593 This->updateStateBlock = This->stateBlock;
6594 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6596 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6597 if(FAILED(hr)) {
6598 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6601 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6603 RECT client_rect;
6604 GetClientRect(swapchain->win_handle, &client_rect);
6606 if(!swapchain->presentParms.BackBufferCount)
6608 TRACE("Single buffered rendering\n");
6609 swapchain->render_to_fbo = FALSE;
6611 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6612 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6614 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6615 swapchain->presentParms.BackBufferWidth,
6616 swapchain->presentParms.BackBufferHeight,
6617 client_rect.right, client_rect.bottom);
6618 swapchain->render_to_fbo = TRUE;
6620 else
6622 TRACE("Rendering directly to GL_BACK\n");
6623 swapchain->render_to_fbo = FALSE;
6627 hr = create_primary_opengl_context(iface, swapchain);
6628 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6630 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6631 * first use
6633 return hr;
6636 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6638 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6640 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6642 return WINED3D_OK;
6646 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6648 TRACE("(%p) : pParameters %p\n", This, pParameters);
6650 *pParameters = This->createParms;
6651 return WINED3D_OK;
6654 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6655 IWineD3DSwapChain *swapchain;
6657 TRACE("Relaying to swapchain\n");
6659 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6660 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6661 IWineD3DSwapChain_Release(swapchain);
6665 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6666 IWineD3DSwapChain *swapchain;
6668 TRACE("Relaying to swapchain\n");
6670 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6671 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6672 IWineD3DSwapChain_Release(swapchain);
6677 /** ********************************************************
6678 * Notification functions
6679 ** ********************************************************/
6680 /** This function must be called in the release of a resource when ref == 0,
6681 * the contents of resource must still be correct,
6682 * any handles to other resource held by the caller must be closed
6683 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6684 *****************************************************/
6685 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6687 TRACE("(%p) : Adding resource %p\n", This, resource);
6689 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6692 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6694 TRACE("(%p) : Removing resource %p\n", This, resource);
6696 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6699 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6701 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6702 int counter;
6704 TRACE("(%p) : resource %p\n", This, resource);
6706 context_resource_released((IWineD3DDevice *)This, resource, type);
6708 switch (type) {
6709 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6710 case WINED3DRTYPE_SURFACE: {
6711 unsigned int i;
6713 if (This->d3d_initialized)
6715 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6717 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6718 This->render_targets[i] = NULL;
6720 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6721 This->depth_stencil = NULL;
6724 break;
6726 case WINED3DRTYPE_TEXTURE:
6727 case WINED3DRTYPE_CUBETEXTURE:
6728 case WINED3DRTYPE_VOLUMETEXTURE:
6729 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6730 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6731 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6732 This->stateBlock->textures[counter] = NULL;
6734 if (This->updateStateBlock != This->stateBlock ){
6735 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6736 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6737 This->updateStateBlock->textures[counter] = NULL;
6741 break;
6742 case WINED3DRTYPE_VOLUME:
6743 /* TODO: nothing really? */
6744 break;
6745 case WINED3DRTYPE_BUFFER:
6747 int streamNumber;
6748 TRACE("Cleaning up stream pointers\n");
6750 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6751 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6752 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6754 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6755 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6756 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6757 This->updateStateBlock->streamSource[streamNumber] = 0;
6758 /* Set changed flag? */
6761 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) */
6762 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6763 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6764 This->stateBlock->streamSource[streamNumber] = 0;
6769 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6770 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6771 This->updateStateBlock->pIndexData = NULL;
6774 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6775 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6776 This->stateBlock->pIndexData = NULL;
6780 break;
6782 default:
6783 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6784 break;
6788 /* Remove the resource from the resourceStore */
6789 device_resource_remove(This, resource);
6791 TRACE("Resource released\n");
6795 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6797 IWineD3DResourceImpl *resource, *cursor;
6798 HRESULT ret;
6799 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6801 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6802 TRACE("enumerating resource %p\n", resource);
6803 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6804 ret = pCallback((IWineD3DResource *) resource, pData);
6805 if(ret == S_FALSE) {
6806 TRACE("Canceling enumeration\n");
6807 break;
6810 return WINED3D_OK;
6813 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6816 IWineD3DResourceImpl *resource;
6818 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6820 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6821 if (type == WINED3DRTYPE_SURFACE)
6823 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6825 TRACE("Found surface %p for dc %p.\n", resource, dc);
6826 *surface = (IWineD3DSurface *)resource;
6827 return WINED3D_OK;
6832 return WINED3DERR_INVALIDCALL;
6835 /**********************************************************
6836 * IWineD3DDevice VTbl follows
6837 **********************************************************/
6839 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6841 /*** IUnknown methods ***/
6842 IWineD3DDeviceImpl_QueryInterface,
6843 IWineD3DDeviceImpl_AddRef,
6844 IWineD3DDeviceImpl_Release,
6845 /*** IWineD3DDevice methods ***/
6846 IWineD3DDeviceImpl_GetParent,
6847 /*** Creation methods**/
6848 IWineD3DDeviceImpl_CreateBuffer,
6849 IWineD3DDeviceImpl_CreateVertexBuffer,
6850 IWineD3DDeviceImpl_CreateIndexBuffer,
6851 IWineD3DDeviceImpl_CreateStateBlock,
6852 IWineD3DDeviceImpl_CreateSurface,
6853 IWineD3DDeviceImpl_CreateRendertargetView,
6854 IWineD3DDeviceImpl_CreateTexture,
6855 IWineD3DDeviceImpl_CreateVolumeTexture,
6856 IWineD3DDeviceImpl_CreateVolume,
6857 IWineD3DDeviceImpl_CreateCubeTexture,
6858 IWineD3DDeviceImpl_CreateQuery,
6859 IWineD3DDeviceImpl_CreateSwapChain,
6860 IWineD3DDeviceImpl_CreateVertexDeclaration,
6861 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6862 IWineD3DDeviceImpl_CreateVertexShader,
6863 IWineD3DDeviceImpl_CreateGeometryShader,
6864 IWineD3DDeviceImpl_CreatePixelShader,
6865 IWineD3DDeviceImpl_CreatePalette,
6866 /*** Odd functions **/
6867 IWineD3DDeviceImpl_Init3D,
6868 IWineD3DDeviceImpl_InitGDI,
6869 IWineD3DDeviceImpl_Uninit3D,
6870 IWineD3DDeviceImpl_UninitGDI,
6871 IWineD3DDeviceImpl_SetMultithreaded,
6872 IWineD3DDeviceImpl_EvictManagedResources,
6873 IWineD3DDeviceImpl_GetAvailableTextureMem,
6874 IWineD3DDeviceImpl_GetBackBuffer,
6875 IWineD3DDeviceImpl_GetCreationParameters,
6876 IWineD3DDeviceImpl_GetDeviceCaps,
6877 IWineD3DDeviceImpl_GetDirect3D,
6878 IWineD3DDeviceImpl_GetDisplayMode,
6879 IWineD3DDeviceImpl_SetDisplayMode,
6880 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6881 IWineD3DDeviceImpl_GetRasterStatus,
6882 IWineD3DDeviceImpl_GetSwapChain,
6883 IWineD3DDeviceImpl_Reset,
6884 IWineD3DDeviceImpl_SetDialogBoxMode,
6885 IWineD3DDeviceImpl_SetCursorProperties,
6886 IWineD3DDeviceImpl_SetCursorPosition,
6887 IWineD3DDeviceImpl_ShowCursor,
6888 /*** Getters and setters **/
6889 IWineD3DDeviceImpl_SetClipPlane,
6890 IWineD3DDeviceImpl_GetClipPlane,
6891 IWineD3DDeviceImpl_SetClipStatus,
6892 IWineD3DDeviceImpl_GetClipStatus,
6893 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6894 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6895 IWineD3DDeviceImpl_SetDepthStencilSurface,
6896 IWineD3DDeviceImpl_GetDepthStencilSurface,
6897 IWineD3DDeviceImpl_SetGammaRamp,
6898 IWineD3DDeviceImpl_GetGammaRamp,
6899 IWineD3DDeviceImpl_SetIndexBuffer,
6900 IWineD3DDeviceImpl_GetIndexBuffer,
6901 IWineD3DDeviceImpl_SetBaseVertexIndex,
6902 IWineD3DDeviceImpl_GetBaseVertexIndex,
6903 IWineD3DDeviceImpl_SetLight,
6904 IWineD3DDeviceImpl_GetLight,
6905 IWineD3DDeviceImpl_SetLightEnable,
6906 IWineD3DDeviceImpl_GetLightEnable,
6907 IWineD3DDeviceImpl_SetMaterial,
6908 IWineD3DDeviceImpl_GetMaterial,
6909 IWineD3DDeviceImpl_SetNPatchMode,
6910 IWineD3DDeviceImpl_GetNPatchMode,
6911 IWineD3DDeviceImpl_SetPaletteEntries,
6912 IWineD3DDeviceImpl_GetPaletteEntries,
6913 IWineD3DDeviceImpl_SetPixelShader,
6914 IWineD3DDeviceImpl_GetPixelShader,
6915 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6916 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6917 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6918 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6919 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6920 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6921 IWineD3DDeviceImpl_SetRenderState,
6922 IWineD3DDeviceImpl_GetRenderState,
6923 IWineD3DDeviceImpl_SetRenderTarget,
6924 IWineD3DDeviceImpl_GetRenderTarget,
6925 IWineD3DDeviceImpl_SetFrontBackBuffers,
6926 IWineD3DDeviceImpl_SetSamplerState,
6927 IWineD3DDeviceImpl_GetSamplerState,
6928 IWineD3DDeviceImpl_SetScissorRect,
6929 IWineD3DDeviceImpl_GetScissorRect,
6930 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6931 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6932 IWineD3DDeviceImpl_SetStreamSource,
6933 IWineD3DDeviceImpl_GetStreamSource,
6934 IWineD3DDeviceImpl_SetStreamSourceFreq,
6935 IWineD3DDeviceImpl_GetStreamSourceFreq,
6936 IWineD3DDeviceImpl_SetTexture,
6937 IWineD3DDeviceImpl_GetTexture,
6938 IWineD3DDeviceImpl_SetTextureStageState,
6939 IWineD3DDeviceImpl_GetTextureStageState,
6940 IWineD3DDeviceImpl_SetTransform,
6941 IWineD3DDeviceImpl_GetTransform,
6942 IWineD3DDeviceImpl_SetVertexDeclaration,
6943 IWineD3DDeviceImpl_GetVertexDeclaration,
6944 IWineD3DDeviceImpl_SetVertexShader,
6945 IWineD3DDeviceImpl_GetVertexShader,
6946 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6947 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6948 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6949 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6950 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6951 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6952 IWineD3DDeviceImpl_SetViewport,
6953 IWineD3DDeviceImpl_GetViewport,
6954 IWineD3DDeviceImpl_MultiplyTransform,
6955 IWineD3DDeviceImpl_ValidateDevice,
6956 IWineD3DDeviceImpl_ProcessVertices,
6957 /*** State block ***/
6958 IWineD3DDeviceImpl_BeginStateBlock,
6959 IWineD3DDeviceImpl_EndStateBlock,
6960 /*** Scene management ***/
6961 IWineD3DDeviceImpl_BeginScene,
6962 IWineD3DDeviceImpl_EndScene,
6963 IWineD3DDeviceImpl_Present,
6964 IWineD3DDeviceImpl_Clear,
6965 IWineD3DDeviceImpl_ClearRendertargetView,
6966 /*** Drawing ***/
6967 IWineD3DDeviceImpl_SetPrimitiveType,
6968 IWineD3DDeviceImpl_GetPrimitiveType,
6969 IWineD3DDeviceImpl_DrawPrimitive,
6970 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6971 IWineD3DDeviceImpl_DrawPrimitiveUP,
6972 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6973 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6974 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6975 IWineD3DDeviceImpl_DrawRectPatch,
6976 IWineD3DDeviceImpl_DrawTriPatch,
6977 IWineD3DDeviceImpl_DeletePatch,
6978 IWineD3DDeviceImpl_ColorFill,
6979 IWineD3DDeviceImpl_UpdateTexture,
6980 IWineD3DDeviceImpl_UpdateSurface,
6981 IWineD3DDeviceImpl_GetFrontBufferData,
6982 /*** object tracking ***/
6983 IWineD3DDeviceImpl_EnumResources,
6984 IWineD3DDeviceImpl_GetSurfaceFromDC,
6985 IWineD3DDeviceImpl_AcquireFocusWindow,
6986 IWineD3DDeviceImpl_ReleaseFocusWindow,
6989 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6990 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6991 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6993 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6994 const struct fragment_pipeline *fragment_pipeline;
6995 struct shader_caps shader_caps;
6996 struct fragment_caps ffp_caps;
6997 WINED3DDISPLAYMODE mode;
6998 unsigned int i;
6999 HRESULT hr;
7001 device->lpVtbl = &IWineD3DDevice_Vtbl;
7002 device->ref = 1;
7003 device->wined3d = (IWineD3D *)wined3d;
7004 IWineD3D_AddRef(device->wined3d);
7005 device->adapter = wined3d->adapter_count ? adapter : NULL;
7006 device->parent = parent;
7007 device->device_parent = device_parent;
7008 list_init(&device->resources);
7009 list_init(&device->shaders);
7011 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7012 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7014 /* Get the initial screen setup for ddraw. */
7015 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7016 if (FAILED(hr))
7018 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7019 IWineD3D_Release(device->wined3d);
7020 return hr;
7022 device->ddraw_width = mode.Width;
7023 device->ddraw_height = mode.Height;
7024 device->ddraw_format = mode.Format;
7026 /* Save the creation parameters. */
7027 device->createParms.AdapterOrdinal = adapter_idx;
7028 device->createParms.DeviceType = device_type;
7029 device->createParms.hFocusWindow = focus_window;
7030 device->createParms.BehaviorFlags = flags;
7032 device->devType = device_type;
7033 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7035 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7036 device->shader_backend = adapter->shader_backend;
7038 if (device->shader_backend)
7040 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7041 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7042 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7043 device->vs_clipping = shader_caps.VSClipping;
7045 fragment_pipeline = adapter->fragment_pipe;
7046 device->frag_pipe = fragment_pipeline;
7047 if (fragment_pipeline)
7049 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7050 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7052 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7053 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7054 if (FAILED(hr))
7056 ERR("Failed to compile state table, hr %#x.\n", hr);
7057 IWineD3D_Release(device->wined3d);
7058 return hr;
7061 device->blitter = adapter->blitter;
7063 return WINED3D_OK;
7067 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7068 DWORD rep = This->StateTable[state].representative;
7069 struct wined3d_context *context;
7070 DWORD idx;
7071 BYTE shift;
7072 UINT i;
7074 for(i = 0; i < This->numContexts; i++) {
7075 context = This->contexts[i];
7076 if(isStateDirty(context, rep)) continue;
7078 context->dirtyArray[context->numDirtyEntries++] = rep;
7079 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7080 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7081 context->isStateDirty[idx] |= (1 << shift);
7085 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7087 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7088 *width = context->current_rt->pow2Width;
7089 *height = context->current_rt->pow2Height;
7092 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7094 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7095 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7096 * current context's drawable, which is the size of the back buffer of the swapchain
7097 * the active context belongs to. */
7098 *width = swapchain->presentParms.BackBufferWidth;
7099 *height = swapchain->presentParms.BackBufferHeight;
7102 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7103 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7105 if (device->filter_messages)
7107 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7108 window, message, wparam, lparam);
7109 return DefWindowProcW(window, message, wparam, lparam);
7112 if (message == WM_DESTROY)
7114 TRACE("unregister window %p.\n", window);
7115 wined3d_unregister_window(window);
7117 if (device->focus_window == window) device->focus_window = NULL;
7118 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7121 return CallWindowProcW(proc, window, message, wparam, lparam);