wined3d: Implement manual buffer fencing.
[wine.git] / dlls / wined3d / device.c
blobd48acf20bfeef247b0d92463851439ded6c01f39
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 unsigned int i;
184 stream_info->use_map = 0;
185 stream_info->swizzle_map = 0;
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info->position_transformed = declaration->position_transformed;
189 if (declaration->position_transformed) use_vshader = FALSE;
191 /* Translate the declaration into strided data. */
192 for (i = 0; i < declaration->element_count; ++i)
194 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!This->stateBlock->streamSource[element->input_slot]) continue;
206 stride = This->stateBlock->streamStride[element->input_slot];
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 buffer_object = 0;
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
216 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
226 buffer_object = 0;
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
234 if (fixup)
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
293 stream_info->elements[idx].format_desc = element->format_desc;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
318 struct wined3d_event_query *query;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
333 query = ((struct wined3d_buffer *) buffer)->query;
334 if(query)
336 This->buffer_queries[This->num_buffer_queries++] = query;
342 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
343 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
345 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
346 e->format_desc = format_desc;
347 e->stride = strided->dwStride;
348 e->data = strided->lpData;
349 e->stream_idx = 0;
350 e->buffer_object = 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
354 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
356 unsigned int i;
358 memset(stream_info, 0, sizeof(*stream_info));
360 if (strided->position.lpData)
361 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
362 if (strided->normal.lpData)
363 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
364 if (strided->diffuse.lpData)
365 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
366 if (strided->specular.lpData)
367 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
369 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
371 if (strided->texCoords[i].lpData)
372 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
373 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
376 stream_info->position_transformed = strided->position_transformed;
378 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
380 if (!stream_info->elements[i].format_desc) continue;
382 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
383 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
385 stream_info->swizzle_map |= 1 << i;
387 stream_info->use_map |= 1 << i;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
414 struct wined3d_stream_info *stream_info = &device->strided_streams;
415 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
416 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
417 BOOL fixup = FALSE;
419 if (device->up_strided)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
424 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
426 else
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
432 if (vs && !stream_info->position_transformed)
434 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device->useDrawStridedSlow = TRUE;
439 else
441 device->useDrawStridedSlow = FALSE;
444 else
446 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
447 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
448 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
450 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
452 device->useDrawStridedSlow = TRUE;
454 else
456 device->useDrawStridedSlow = FALSE;
461 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
463 IWineD3DBaseTextureImpl *texture;
464 enum WINED3DSRGB srgb;
466 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
467 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
468 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
471 void device_preload_textures(IWineD3DDeviceImpl *device)
473 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
474 unsigned int i;
476 if (use_vs(stateblock))
478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
480 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
481 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
485 if (use_ps(stateblock))
487 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
489 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, i);
493 else
495 WORD ffu_map = device->fixed_function_usage_map;
497 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
499 if (ffu_map & 1)
500 device_preload_texture(stateblock, i);
505 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
507 struct wined3d_context **new_array;
509 TRACE("Adding context %p.\n", context);
511 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
512 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
514 if (!new_array)
516 ERR("Failed to grow the context array.\n");
517 return FALSE;
520 new_array[device->numContexts++] = context;
521 device->contexts = new_array;
522 return TRUE;
525 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
527 struct wined3d_context **new_array;
528 BOOL found = FALSE;
529 UINT i;
531 TRACE("Removing context %p.\n", context);
533 for (i = 0; i < device->numContexts; ++i)
535 if (device->contexts[i] == context)
537 found = TRUE;
538 break;
542 if (!found)
544 ERR("Context %p doesn't exist in context array.\n", context);
545 return;
548 if (!--device->numContexts)
550 HeapFree(GetProcessHeap(), 0, device->contexts);
551 device->contexts = NULL;
552 return;
555 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
556 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
557 if (!new_array)
559 ERR("Failed to shrink context array. Oh well.\n");
560 return;
563 device->contexts = new_array;
567 /**********************************************************
568 * IUnknown parts follows
569 **********************************************************/
571 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
575 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
576 if (IsEqualGUID(riid, &IID_IUnknown)
577 || IsEqualGUID(riid, &IID_IWineD3DBase)
578 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
579 IUnknown_AddRef(iface);
580 *ppobj = This;
581 return S_OK;
583 *ppobj = NULL;
584 return E_NOINTERFACE;
587 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 ULONG refCount = InterlockedIncrement(&This->ref);
591 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
592 return refCount;
595 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 ULONG refCount = InterlockedDecrement(&This->ref);
599 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
601 if (!refCount) {
602 UINT i;
604 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
605 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
606 This->multistate_funcs[i] = NULL;
609 /* TODO: Clean up all the surfaces and textures! */
610 /* NOTE: You must release the parent if the object was created via a callback
611 ** ***************************/
613 if (!list_empty(&This->resources)) {
614 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
615 dumpResources(&This->resources);
618 if(This->contexts) ERR("Context array not freed!\n");
619 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
620 This->haveHardwareCursor = FALSE;
622 IWineD3D_Release(This->wined3d);
623 This->wined3d = NULL;
624 HeapFree(GetProcessHeap(), 0, This);
625 TRACE("Freed device %p\n", This);
626 This = NULL;
628 return refCount;
631 /**********************************************************
632 * IWineD3DDevice implementation follows
633 **********************************************************/
634 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
636 *pParent = This->parent;
637 IUnknown_AddRef(This->parent);
638 return WINED3D_OK;
641 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
642 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
645 struct wined3d_buffer *object;
646 HRESULT hr;
648 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
650 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
651 if (!object)
653 ERR("Failed to allocate memory\n");
654 return E_OUTOFMEMORY;
657 FIXME("Ignoring access flags (pool)\n");
659 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
660 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
661 if (FAILED(hr))
663 WARN("Failed to initialize buffer, hr %#x.\n", hr);
664 HeapFree(GetProcessHeap(), 0, object);
665 return hr;
667 object->desc = *desc;
669 TRACE("Created buffer %p.\n", object);
671 *buffer = (IWineD3DBuffer *)object;
673 return WINED3D_OK;
676 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
677 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
678 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
681 struct wined3d_buffer *object;
682 HRESULT hr;
684 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
685 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
687 if (Pool == WINED3DPOOL_SCRATCH)
689 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
690 * anyway, SCRATCH vertex buffers aren't usable anywhere
692 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
693 *ppVertexBuffer = NULL;
694 return WINED3DERR_INVALIDCALL;
697 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
698 if (!object)
700 ERR("Out of memory\n");
701 *ppVertexBuffer = NULL;
702 return WINED3DERR_OUTOFVIDEOMEMORY;
705 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
706 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
707 if (FAILED(hr))
709 WARN("Failed to initialize buffer, hr %#x.\n", hr);
710 HeapFree(GetProcessHeap(), 0, object);
711 return hr;
714 TRACE("Created buffer %p.\n", object);
715 *ppVertexBuffer = (IWineD3DBuffer *)object;
717 return WINED3D_OK;
720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
721 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
722 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
725 struct wined3d_buffer *object;
726 HRESULT hr;
728 TRACE("(%p) Creating index buffer\n", This);
730 /* Allocate the storage for the device */
731 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
732 if (!object)
734 ERR("Out of memory\n");
735 *ppIndexBuffer = NULL;
736 return WINED3DERR_OUTOFVIDEOMEMORY;
739 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
740 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
741 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);
751 *ppIndexBuffer = (IWineD3DBuffer *) object;
753 return WINED3D_OK;
756 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
757 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 IWineD3DStateBlockImpl *object;
761 HRESULT hr;
763 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
764 if(!object)
766 ERR("Failed to allocate stateblock memory.\n");
767 return E_OUTOFMEMORY;
770 hr = stateblock_init(object, This, type);
771 if (FAILED(hr))
773 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
774 HeapFree(GetProcessHeap(), 0, object);
775 return hr;
778 TRACE("Created stateblock %p.\n", object);
779 *stateblock = (IWineD3DStateBlock *)object;
781 return WINED3D_OK;
784 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
785 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
786 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
787 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
790 IWineD3DSurfaceImpl *object;
791 HRESULT hr;
793 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
794 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
795 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
796 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
797 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
799 if (Impl == SURFACE_OPENGL && !This->adapter)
801 ERR("OpenGL surfaces are not available without OpenGL.\n");
802 return WINED3DERR_NOTAVAILABLE;
805 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
806 if (!object)
808 ERR("Failed to allocate surface memory.\n");
809 return WINED3DERR_OUTOFVIDEOMEMORY;
812 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
813 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
814 if (FAILED(hr))
816 WARN("Failed to initialize surface, returning %#x.\n", hr);
817 HeapFree(GetProcessHeap(), 0, object);
818 return hr;
821 TRACE("(%p) : Created surface %p\n", This, object);
823 *ppSurface = (IWineD3DSurface *)object;
825 return hr;
828 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
829 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
831 struct wined3d_rendertarget_view *object;
833 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
834 if (!object)
836 ERR("Failed to allocate memory\n");
837 return E_OUTOFMEMORY;
840 object->vtbl = &wined3d_rendertarget_view_vtbl;
841 object->refcount = 1;
842 IWineD3DResource_AddRef(resource);
843 object->resource = resource;
844 object->parent = parent;
846 *rendertarget_view = (IWineD3DRendertargetView *)object;
848 return WINED3D_OK;
851 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
852 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
853 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 IWineD3DTextureImpl *object;
857 HRESULT hr;
859 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
860 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
861 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
863 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
864 if (!object)
866 ERR("Out of memory\n");
867 *ppTexture = NULL;
868 return WINED3DERR_OUTOFVIDEOMEMORY;
871 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
872 if (FAILED(hr))
874 WARN("Failed to initialize texture, returning %#x\n", hr);
875 HeapFree(GetProcessHeap(), 0, object);
876 *ppTexture = NULL;
877 return hr;
880 *ppTexture = (IWineD3DTexture *)object;
882 TRACE("(%p) : Created texture %p\n", This, object);
884 return WINED3D_OK;
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
889 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
892 IWineD3DVolumeTextureImpl *object;
893 HRESULT hr;
895 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
896 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
899 if (!object)
901 ERR("Out of memory\n");
902 *ppVolumeTexture = NULL;
903 return WINED3DERR_OUTOFVIDEOMEMORY;
906 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
907 if (FAILED(hr))
909 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
910 HeapFree(GetProcessHeap(), 0, object);
911 *ppVolumeTexture = NULL;
912 return hr;
915 TRACE("(%p) : Created volume texture %p.\n", This, object);
916 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
918 return WINED3D_OK;
921 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
922 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
923 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
926 IWineD3DVolumeImpl *object;
927 HRESULT hr;
929 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
930 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
932 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
933 if (!object)
935 ERR("Out of memory\n");
936 *ppVolume = NULL;
937 return WINED3DERR_OUTOFVIDEOMEMORY;
940 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
941 if (FAILED(hr))
943 WARN("Failed to initialize volume, returning %#x.\n", hr);
944 HeapFree(GetProcessHeap(), 0, object);
945 return hr;
948 TRACE("(%p) : Created volume %p.\n", This, object);
949 *ppVolume = (IWineD3DVolume *)object;
951 return WINED3D_OK;
954 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
955 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
956 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
959 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
960 HRESULT hr;
962 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
963 if (!object)
965 ERR("Out of memory\n");
966 *ppCubeTexture = NULL;
967 return WINED3DERR_OUTOFVIDEOMEMORY;
970 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
971 if (FAILED(hr))
973 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
974 HeapFree(GetProcessHeap(), 0, object);
975 *ppCubeTexture = NULL;
976 return hr;
979 TRACE("(%p) : Created Cube Texture %p\n", This, object);
980 *ppCubeTexture = (IWineD3DCubeTexture *)object;
982 return WINED3D_OK;
985 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
986 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
989 IWineD3DQueryImpl *object;
990 HRESULT hr;
992 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
994 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
995 if (!object)
997 ERR("Failed to allocate query memory.\n");
998 return E_OUTOFMEMORY;
1001 hr = query_init(object, This, type, parent);
1002 if (FAILED(hr))
1004 WARN("Failed to initialize query, hr %#x.\n", hr);
1005 HeapFree(GetProcessHeap(), 0, object);
1006 return hr;
1009 TRACE("Created query %p.\n", object);
1010 *query = (IWineD3DQuery *)object;
1012 return WINED3D_OK;
1015 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1016 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1017 IUnknown *parent, WINED3DSURFTYPE surface_type)
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DSwapChainImpl *object;
1021 HRESULT hr;
1023 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1024 iface, present_parameters, swapchain, parent, surface_type);
1026 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1027 if (!object)
1029 ERR("Failed to allocate swapchain memory.\n");
1030 return E_OUTOFMEMORY;
1033 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1034 if (FAILED(hr))
1036 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1037 HeapFree(GetProcessHeap(), 0, object);
1038 return hr;
1041 TRACE("Created swapchain %p.\n", object);
1042 *swapchain = (IWineD3DSwapChain *)object;
1044 return WINED3D_OK;
1047 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1048 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1050 TRACE("(%p)\n", This);
1052 return This->NumberOfSwapChains;
1055 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1057 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1059 if(iSwapChain < This->NumberOfSwapChains) {
1060 *pSwapChain = This->swapchains[iSwapChain];
1061 IWineD3DSwapChain_AddRef(*pSwapChain);
1062 TRACE("(%p) returning %p\n", This, *pSwapChain);
1063 return WINED3D_OK;
1064 } else {
1065 TRACE("Swapchain out of range\n");
1066 *pSwapChain = NULL;
1067 return WINED3DERR_INVALIDCALL;
1071 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1072 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1073 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1076 IWineD3DVertexDeclarationImpl *object = NULL;
1077 HRESULT hr;
1079 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1080 iface, declaration, parent, elements, element_count);
1082 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1083 if(!object)
1085 ERR("Failed to allocate vertex declaration memory.\n");
1086 return E_OUTOFMEMORY;
1089 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1090 if (FAILED(hr))
1092 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1093 HeapFree(GetProcessHeap(), 0, object);
1094 return hr;
1097 TRACE("Created vertex declaration %p.\n", object);
1098 *declaration = (IWineD3DVertexDeclaration *)object;
1100 return WINED3D_OK;
1103 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1104 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1106 unsigned int idx, idx2;
1107 unsigned int offset;
1108 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1109 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1110 BOOL has_blend_idx = has_blend &&
1111 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1112 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1113 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1114 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1115 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1116 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1117 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1119 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1120 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1121 WINED3DVERTEXELEMENT *elements = NULL;
1123 unsigned int size;
1124 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1125 if (has_blend_idx) num_blends--;
1127 /* Compute declaration size */
1128 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1129 has_psize + has_diffuse + has_specular + num_textures;
1131 /* convert the declaration */
1132 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1133 if (!elements) return ~0U;
1135 idx = 0;
1136 if (has_pos) {
1137 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1138 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1139 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1141 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1142 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1143 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1145 else {
1146 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1147 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1149 elements[idx].usage_idx = 0;
1150 idx++;
1152 if (has_blend && (num_blends > 0)) {
1153 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1154 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1155 else {
1156 switch(num_blends) {
1157 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1158 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1159 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1160 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1161 default:
1162 ERR("Unexpected amount of blend values: %u\n", num_blends);
1165 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1166 elements[idx].usage_idx = 0;
1167 idx++;
1169 if (has_blend_idx) {
1170 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1171 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1172 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1173 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1174 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1175 else
1176 elements[idx].format = WINED3DFMT_R32_FLOAT;
1177 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1178 elements[idx].usage_idx = 0;
1179 idx++;
1181 if (has_normal) {
1182 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1183 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1184 elements[idx].usage_idx = 0;
1185 idx++;
1187 if (has_psize) {
1188 elements[idx].format = WINED3DFMT_R32_FLOAT;
1189 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1190 elements[idx].usage_idx = 0;
1191 idx++;
1193 if (has_diffuse) {
1194 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1195 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1196 elements[idx].usage_idx = 0;
1197 idx++;
1199 if (has_specular) {
1200 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1201 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1202 elements[idx].usage_idx = 1;
1203 idx++;
1205 for (idx2 = 0; idx2 < num_textures; idx2++) {
1206 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1207 switch (numcoords) {
1208 case WINED3DFVF_TEXTUREFORMAT1:
1209 elements[idx].format = WINED3DFMT_R32_FLOAT;
1210 break;
1211 case WINED3DFVF_TEXTUREFORMAT2:
1212 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1213 break;
1214 case WINED3DFVF_TEXTUREFORMAT3:
1215 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1216 break;
1217 case WINED3DFVF_TEXTUREFORMAT4:
1218 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1219 break;
1221 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1222 elements[idx].usage_idx = idx2;
1223 idx++;
1226 /* Now compute offsets, and initialize the rest of the fields */
1227 for (idx = 0, offset = 0; idx < size; ++idx)
1229 const struct wined3d_format_desc *format_desc = getFormatDescEntry(elements[idx].format,
1230 &This->adapter->gl_info);
1231 elements[idx].input_slot = 0;
1232 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1233 elements[idx].offset = offset;
1234 offset += format_desc->component_count * format_desc->component_size;
1237 *ppVertexElements = elements;
1238 return size;
1241 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1242 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1243 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1246 WINED3DVERTEXELEMENT *elements;
1247 unsigned int size;
1248 DWORD hr;
1250 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1252 size = ConvertFvfToDeclaration(This, fvf, &elements);
1253 if (size == ~0U) return E_OUTOFMEMORY;
1255 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1256 HeapFree(GetProcessHeap(), 0, elements);
1257 return hr;
1260 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1261 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1262 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1263 const struct wined3d_parent_ops *parent_ops)
1265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1266 IWineD3DVertexShaderImpl *object;
1267 HRESULT hr;
1269 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1270 if (!object)
1272 ERR("Failed to allocate shader memory.\n");
1273 return E_OUTOFMEMORY;
1276 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1277 if (FAILED(hr))
1279 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1280 HeapFree(GetProcessHeap(), 0, object);
1281 return hr;
1284 TRACE("Created vertex shader %p.\n", object);
1285 *ppVertexShader = (IWineD3DVertexShader *)object;
1287 return WINED3D_OK;
1290 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1291 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1292 IWineD3DGeometryShader **shader, IUnknown *parent,
1293 const struct wined3d_parent_ops *parent_ops)
1295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 struct wined3d_geometryshader *object;
1297 HRESULT hr;
1299 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1300 if (!object)
1302 ERR("Failed to allocate shader memory.\n");
1303 return E_OUTOFMEMORY;
1306 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1307 if (FAILED(hr))
1309 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1310 HeapFree(GetProcessHeap(), 0, object);
1311 return hr;
1314 TRACE("Created geometry shader %p.\n", object);
1315 *shader = (IWineD3DGeometryShader *)object;
1317 return WINED3D_OK;
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1321 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1322 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1323 const struct wined3d_parent_ops *parent_ops)
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 IWineD3DPixelShaderImpl *object;
1327 HRESULT hr;
1329 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1330 if (!object)
1332 ERR("Failed to allocate shader memory.\n");
1333 return E_OUTOFMEMORY;
1336 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1337 if (FAILED(hr))
1339 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1340 HeapFree(GetProcessHeap(), 0, object);
1341 return hr;
1344 TRACE("Created pixel shader %p.\n", object);
1345 *ppPixelShader = (IWineD3DPixelShader *)object;
1347 return WINED3D_OK;
1350 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1351 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1354 IWineD3DPaletteImpl *object;
1355 HRESULT hr;
1356 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1358 /* Create the new object */
1359 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1360 if(!object) {
1361 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1362 return E_OUTOFMEMORY;
1365 object->lpVtbl = &IWineD3DPalette_Vtbl;
1366 object->ref = 1;
1367 object->Flags = Flags;
1368 object->parent = Parent;
1369 object->device = This;
1370 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1371 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1373 if(!object->hpal) {
1374 HeapFree( GetProcessHeap(), 0, object);
1375 return E_OUTOFMEMORY;
1378 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1379 if(FAILED(hr)) {
1380 IWineD3DPalette_Release((IWineD3DPalette *) object);
1381 return hr;
1384 *Palette = (IWineD3DPalette *) object;
1386 return WINED3D_OK;
1389 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1390 HBITMAP hbm;
1391 BITMAP bm;
1392 HRESULT hr;
1393 HDC dcb = NULL, dcs = NULL;
1394 WINEDDCOLORKEY colorkey;
1396 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1397 if(hbm)
1399 GetObjectA(hbm, sizeof(BITMAP), &bm);
1400 dcb = CreateCompatibleDC(NULL);
1401 if(!dcb) goto out;
1402 SelectObject(dcb, hbm);
1404 else
1406 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1407 * couldn't be loaded
1409 memset(&bm, 0, sizeof(bm));
1410 bm.bmWidth = 32;
1411 bm.bmHeight = 32;
1414 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1415 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1416 NULL, &wined3d_null_parent_ops);
1417 if(FAILED(hr)) {
1418 ERR("Wine logo requested, but failed to create surface\n");
1419 goto out;
1422 if(dcb) {
1423 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1424 if(FAILED(hr)) goto out;
1425 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1426 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1428 colorkey.dwColorSpaceLowValue = 0;
1429 colorkey.dwColorSpaceHighValue = 0;
1430 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1431 } else {
1432 /* Fill the surface with a white color to show that wined3d is there */
1433 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1436 out:
1437 if (dcb) DeleteDC(dcb);
1438 if (hbm) DeleteObject(hbm);
1441 /* Context activation is done by the caller. */
1442 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1444 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1445 unsigned int i;
1446 /* Under DirectX you can have texture stage operations even if no texture is
1447 bound, whereas opengl will only do texture operations when a valid texture is
1448 bound. We emulate this by creating dummy textures and binding them to each
1449 texture stage, but disable all stages by default. Hence if a stage is enabled
1450 then the default texture will kick in until replaced by a SetTexture call */
1451 ENTER_GL();
1453 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1455 /* The dummy texture does not have client storage backing */
1456 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1457 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1460 for (i = 0; i < gl_info->limits.textures; ++i)
1462 GLubyte white = 255;
1464 /* Make appropriate texture active */
1465 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1466 checkGLcall("glActiveTextureARB");
1468 /* Generate an opengl texture name */
1469 glGenTextures(1, &This->dummyTextureName[i]);
1470 checkGLcall("glGenTextures");
1471 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1473 /* Generate a dummy 2d texture (not using 1d because they cause many
1474 * DRI drivers fall back to sw) */
1475 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1476 checkGLcall("glBindTexture");
1478 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1479 checkGLcall("glTexImage2D");
1482 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1484 /* Reenable because if supported it is enabled by default */
1485 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1486 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1489 LEAVE_GL();
1492 /* Context activation is done by the caller. */
1493 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1495 ENTER_GL();
1496 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1497 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1498 LEAVE_GL();
1500 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1503 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1505 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1507 if (!wined3d_register_window(window, device))
1509 ERR("Failed to register window %p.\n", window);
1510 return E_FAIL;
1513 device->focus_window = window;
1514 SetForegroundWindow(window);
1516 return WINED3D_OK;
1519 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1521 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1523 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1524 device->focus_window = NULL;
1527 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1528 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1531 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1532 IWineD3DSwapChainImpl *swapchain = NULL;
1533 struct wined3d_context *context;
1534 HRESULT hr;
1535 DWORD state;
1536 unsigned int i;
1538 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1540 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1541 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1543 TRACE("(%p) : Creating stateblock\n", This);
1544 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1545 hr = IWineD3DDevice_CreateStateBlock(iface,
1546 WINED3DSBT_INIT,
1547 (IWineD3DStateBlock **)&This->stateBlock,
1548 NULL);
1549 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1550 WARN("Failed to create stateblock\n");
1551 goto err_out;
1553 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1554 This->updateStateBlock = This->stateBlock;
1555 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1557 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1558 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1559 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1560 sizeof(GLenum) * gl_info->limits.buffers);
1562 This->NumberOfPalettes = 1;
1563 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1564 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1565 ERR("Out of memory!\n");
1566 hr = E_OUTOFMEMORY;
1567 goto err_out;
1569 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1570 if(!This->palettes[0]) {
1571 ERR("Out of memory!\n");
1572 hr = E_OUTOFMEMORY;
1573 goto err_out;
1575 for (i = 0; i < 256; ++i) {
1576 This->palettes[0][i].peRed = 0xFF;
1577 This->palettes[0][i].peGreen = 0xFF;
1578 This->palettes[0][i].peBlue = 0xFF;
1579 This->palettes[0][i].peFlags = 0xFF;
1581 This->currentPalette = 0;
1583 /* Initialize the texture unit mapping to a 1:1 mapping */
1584 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1586 if (state < gl_info->limits.fragment_samplers)
1588 This->texUnitMap[state] = state;
1589 This->rev_tex_unit_map[state] = state;
1590 } else {
1591 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1592 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1596 /* Setup the implicit swapchain. This also initializes a context. */
1597 TRACE("Creating implicit swapchain\n");
1598 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1599 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1600 if (FAILED(hr))
1602 WARN("Failed to create implicit swapchain\n");
1603 goto err_out;
1606 This->NumberOfSwapChains = 1;
1607 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1608 if(!This->swapchains) {
1609 ERR("Out of memory!\n");
1610 goto err_out;
1612 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1614 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1615 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1616 This->render_targets[0] = swapchain->backBuffer[0];
1618 else {
1619 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1620 This->render_targets[0] = swapchain->frontBuffer;
1622 IWineD3DSurface_AddRef(This->render_targets[0]);
1624 /* Depth Stencil support */
1625 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1626 if (NULL != This->stencilBufferTarget) {
1627 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1630 hr = This->shader_backend->shader_alloc_private(iface);
1631 if(FAILED(hr)) {
1632 TRACE("Shader private data couldn't be allocated\n");
1633 goto err_out;
1635 hr = This->frag_pipe->alloc_private(iface);
1636 if(FAILED(hr)) {
1637 TRACE("Fragment pipeline private data couldn't be allocated\n");
1638 goto err_out;
1640 hr = This->blitter->alloc_private(iface);
1641 if(FAILED(hr)) {
1642 TRACE("Blitter private data couldn't be allocated\n");
1643 goto err_out;
1646 /* Set up some starting GL setup */
1648 /* Setup all the devices defaults */
1649 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1651 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1653 create_dummy_textures(This);
1655 ENTER_GL();
1657 /* Initialize the current view state */
1658 This->view_ident = 1;
1659 This->contexts[0]->last_was_rhw = 0;
1660 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1661 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1663 switch(wined3d_settings.offscreen_rendering_mode) {
1664 case ORM_FBO:
1665 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1666 break;
1668 case ORM_BACKBUFFER:
1670 if (context_get_current()->aux_buffers > 0)
1672 TRACE("Using auxilliary buffer for offscreen rendering\n");
1673 This->offscreenBuffer = GL_AUX0;
1674 } else {
1675 TRACE("Using back buffer for offscreen rendering\n");
1676 This->offscreenBuffer = GL_BACK;
1681 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1682 LEAVE_GL();
1684 context_release(context);
1686 /* Clear the screen */
1687 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1688 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1689 0x00, 1.0f, 0);
1691 This->d3d_initialized = TRUE;
1693 if(wined3d_settings.logo) {
1694 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1696 This->highest_dirty_ps_const = 0;
1697 This->highest_dirty_vs_const = 0;
1698 return WINED3D_OK;
1700 err_out:
1701 HeapFree(GetProcessHeap(), 0, This->render_targets);
1702 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1703 HeapFree(GetProcessHeap(), 0, This->swapchains);
1704 This->NumberOfSwapChains = 0;
1705 if(This->palettes) {
1706 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1707 HeapFree(GetProcessHeap(), 0, This->palettes);
1709 This->NumberOfPalettes = 0;
1710 if(swapchain) {
1711 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1713 if(This->stateBlock) {
1714 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1715 This->stateBlock = NULL;
1717 if (This->blit_priv) {
1718 This->blitter->free_private(iface);
1720 if (This->fragment_priv) {
1721 This->frag_pipe->free_private(iface);
1723 if (This->shader_priv) {
1724 This->shader_backend->shader_free_private(iface);
1726 return hr;
1729 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1730 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1733 IWineD3DSwapChainImpl *swapchain = NULL;
1734 HRESULT hr;
1736 /* Setup the implicit swapchain */
1737 TRACE("Creating implicit swapchain\n");
1738 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1739 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1740 if (FAILED(hr))
1742 WARN("Failed to create implicit swapchain\n");
1743 goto err_out;
1746 This->NumberOfSwapChains = 1;
1747 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1748 if(!This->swapchains) {
1749 ERR("Out of memory!\n");
1750 goto err_out;
1752 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1753 return WINED3D_OK;
1755 err_out:
1756 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1757 return hr;
1760 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1762 IWineD3DResource_UnLoad(resource);
1763 IWineD3DResource_Release(resource);
1764 return WINED3D_OK;
1767 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1768 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1771 const struct wined3d_gl_info *gl_info;
1772 struct wined3d_context *context;
1773 int sampler;
1774 UINT i;
1775 TRACE("(%p)\n", This);
1777 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1779 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1780 * it was created. Thus make sure a context is active for the glDelete* calls
1782 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1783 gl_info = context->gl_info;
1785 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1787 /* Unload resources */
1788 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1790 TRACE("Deleting high order patches\n");
1791 for(i = 0; i < PATCHMAP_SIZE; i++) {
1792 struct list *e1, *e2;
1793 struct WineD3DRectPatch *patch;
1794 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1795 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1796 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1800 /* Delete the mouse cursor texture */
1801 if(This->cursorTexture) {
1802 ENTER_GL();
1803 glDeleteTextures(1, &This->cursorTexture);
1804 LEAVE_GL();
1805 This->cursorTexture = 0;
1808 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1809 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1811 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1812 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1815 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1816 * private data, it might contain opengl pointers
1818 if(This->depth_blt_texture) {
1819 ENTER_GL();
1820 glDeleteTextures(1, &This->depth_blt_texture);
1821 LEAVE_GL();
1822 This->depth_blt_texture = 0;
1824 if (This->depth_blt_rb) {
1825 ENTER_GL();
1826 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1827 LEAVE_GL();
1828 This->depth_blt_rb = 0;
1829 This->depth_blt_rb_w = 0;
1830 This->depth_blt_rb_h = 0;
1833 /* Release the update stateblock */
1834 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1835 if(This->updateStateBlock != This->stateBlock)
1836 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1838 This->updateStateBlock = NULL;
1840 { /* because were not doing proper internal refcounts releasing the primary state block
1841 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1842 to set this->stateBlock = NULL; first */
1843 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1844 This->stateBlock = NULL;
1846 /* Release the stateblock */
1847 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1848 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1852 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1853 This->blitter->free_private(iface);
1854 This->frag_pipe->free_private(iface);
1855 This->shader_backend->shader_free_private(iface);
1857 /* Release the buffers (with sanity checks)*/
1858 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1859 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1860 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1861 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1863 This->stencilBufferTarget = NULL;
1865 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1866 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1867 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1869 TRACE("Setting rendertarget to NULL\n");
1870 This->render_targets[0] = NULL;
1872 if (This->auto_depth_stencil_buffer) {
1873 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1875 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1877 This->auto_depth_stencil_buffer = NULL;
1880 context_release(context);
1882 for(i=0; i < This->NumberOfSwapChains; i++) {
1883 TRACE("Releasing the implicit swapchain %d\n", i);
1884 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1885 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1889 HeapFree(GetProcessHeap(), 0, This->swapchains);
1890 This->swapchains = NULL;
1891 This->NumberOfSwapChains = 0;
1893 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1894 HeapFree(GetProcessHeap(), 0, This->palettes);
1895 This->palettes = NULL;
1896 This->NumberOfPalettes = 0;
1898 HeapFree(GetProcessHeap(), 0, This->render_targets);
1899 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1900 This->render_targets = NULL;
1901 This->draw_buffers = NULL;
1903 This->d3d_initialized = FALSE;
1905 return WINED3D_OK;
1908 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1910 unsigned int i;
1912 for(i=0; i < This->NumberOfSwapChains; i++) {
1913 TRACE("Releasing the implicit swapchain %d\n", i);
1914 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1915 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1919 HeapFree(GetProcessHeap(), 0, This->swapchains);
1920 This->swapchains = NULL;
1921 This->NumberOfSwapChains = 0;
1922 return WINED3D_OK;
1925 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1926 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1927 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1929 * There is no way to deactivate thread safety once it is enabled.
1931 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1934 /*For now just store the flag(needed in case of ddraw) */
1935 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1939 const WINED3DDISPLAYMODE* pMode) {
1940 DEVMODEW devmode;
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1942 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1943 LONG ret;
1944 RECT clip_rc;
1946 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1948 /* Resize the screen even without a window:
1949 * The app could have unset it with SetCooperativeLevel, but not called
1950 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1951 * but we don't have any hwnd
1954 memset(&devmode, 0, sizeof(devmode));
1955 devmode.dmSize = sizeof(devmode);
1956 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1957 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1958 devmode.dmPelsWidth = pMode->Width;
1959 devmode.dmPelsHeight = pMode->Height;
1961 devmode.dmDisplayFrequency = pMode->RefreshRate;
1962 if (pMode->RefreshRate != 0) {
1963 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1966 /* Only change the mode if necessary */
1967 if( (This->ddraw_width == pMode->Width) &&
1968 (This->ddraw_height == pMode->Height) &&
1969 (This->ddraw_format == pMode->Format) &&
1970 (pMode->RefreshRate == 0) ) {
1971 return WINED3D_OK;
1974 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1975 if (ret != DISP_CHANGE_SUCCESSFUL) {
1976 if(devmode.dmDisplayFrequency != 0) {
1977 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1978 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1979 devmode.dmDisplayFrequency = 0;
1980 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1982 if(ret != DISP_CHANGE_SUCCESSFUL) {
1983 return WINED3DERR_NOTAVAILABLE;
1987 /* Store the new values */
1988 This->ddraw_width = pMode->Width;
1989 This->ddraw_height = pMode->Height;
1990 This->ddraw_format = pMode->Format;
1992 /* And finally clip mouse to our screen */
1993 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1994 ClipCursor(&clip_rc);
1996 return WINED3D_OK;
1999 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2001 *ppD3D = This->wined3d;
2002 TRACE("Returning %p.\n", *ppD3D);
2003 IWineD3D_AddRef(*ppD3D);
2004 return WINED3D_OK;
2007 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2010 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2011 (This->adapter->TextureRam/(1024*1024)),
2012 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2013 /* return simulated texture memory left */
2014 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2017 /*****
2018 * Get / Set Stream Source
2019 *****/
2020 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2021 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2024 IWineD3DBuffer *oldSrc;
2026 if (StreamNumber >= MAX_STREAMS) {
2027 WARN("Stream out of range %d\n", StreamNumber);
2028 return WINED3DERR_INVALIDCALL;
2029 } else if(OffsetInBytes & 0x3) {
2030 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2031 return WINED3DERR_INVALIDCALL;
2034 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2035 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2037 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2039 if(oldSrc == pStreamData &&
2040 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2041 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2042 TRACE("Application is setting the old values over, nothing to do\n");
2043 return WINED3D_OK;
2046 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2047 if (pStreamData) {
2048 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2049 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2052 /* Handle recording of state blocks */
2053 if (This->isRecordingState) {
2054 TRACE("Recording... not performing anything\n");
2055 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2056 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2057 return WINED3D_OK;
2060 if (pStreamData != NULL) {
2061 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2062 IWineD3DBuffer_AddRef(pStreamData);
2064 if (oldSrc != NULL) {
2065 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2066 IWineD3DBuffer_Release(oldSrc);
2069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2071 return WINED3D_OK;
2074 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2075 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2080 This->stateBlock->streamSource[StreamNumber],
2081 This->stateBlock->streamOffset[StreamNumber],
2082 This->stateBlock->streamStride[StreamNumber]);
2084 if (StreamNumber >= MAX_STREAMS) {
2085 WARN("Stream out of range %d\n", StreamNumber);
2086 return WINED3DERR_INVALIDCALL;
2088 *pStream = This->stateBlock->streamSource[StreamNumber];
2089 *pStride = This->stateBlock->streamStride[StreamNumber];
2090 if (pOffset) {
2091 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2094 if (*pStream != NULL) {
2095 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2097 return WINED3D_OK;
2100 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2102 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2103 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2105 /* Verify input at least in d3d9 this is invalid*/
2106 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2107 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2108 return WINED3DERR_INVALIDCALL;
2110 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2111 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2112 return WINED3DERR_INVALIDCALL;
2114 if( Divider == 0 ){
2115 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2116 return WINED3DERR_INVALIDCALL;
2119 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2120 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2122 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2123 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2125 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2126 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2130 return WINED3D_OK;
2133 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2136 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2137 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2139 TRACE("(%p) : returning %d\n", This, *Divider);
2141 return WINED3D_OK;
2144 /*****
2145 * Get / Set & Multiply Transform
2146 *****/
2147 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2150 /* Most of this routine, comments included copied from ddraw tree initially: */
2151 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2153 /* Handle recording of state blocks */
2154 if (This->isRecordingState) {
2155 TRACE("Recording... not performing anything\n");
2156 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2157 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2158 return WINED3D_OK;
2162 * If the new matrix is the same as the current one,
2163 * we cut off any further processing. this seems to be a reasonable
2164 * optimization because as was noticed, some apps (warcraft3 for example)
2165 * tend towards setting the same matrix repeatedly for some reason.
2167 * From here on we assume that the new matrix is different, wherever it matters.
2169 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2170 TRACE("The app is setting the same matrix over again\n");
2171 return WINED3D_OK;
2172 } else {
2173 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2177 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2178 where ViewMat = Camera space, WorldMat = world space.
2180 In OpenGL, camera and world space is combined into GL_MODELVIEW
2181 matrix. The Projection matrix stay projection matrix.
2184 /* Capture the times we can just ignore the change for now */
2185 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2186 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2187 /* Handled by the state manager */
2190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2191 return WINED3D_OK;
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2197 *pMatrix = This->stateBlock->transforms[State];
2198 return WINED3D_OK;
2201 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2202 const WINED3DMATRIX *mat = NULL;
2203 WINED3DMATRIX temp;
2205 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2206 * below means it will be recorded in a state block change, but it
2207 * works regardless where it is recorded.
2208 * If this is found to be wrong, change to StateBlock.
2210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2211 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2213 if (State <= HIGHEST_TRANSFORMSTATE)
2215 mat = &This->updateStateBlock->transforms[State];
2216 } else {
2217 FIXME("Unhandled transform state!!\n");
2220 multiply_matrix(&temp, mat, pMatrix);
2222 /* Apply change via set transform - will reapply to eg. lights this way */
2223 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2226 /*****
2227 * Get / Set Light
2228 *****/
2229 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2230 you can reference any indexes you want as long as that number max are enabled at any
2231 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2232 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2233 but when recording, just build a chain pretty much of commands to be replayed. */
2235 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2236 float rho;
2237 struct wined3d_light_info *object = NULL;
2238 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2239 struct list *e;
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2242 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2244 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2245 * the gl driver.
2247 if(!pLight) {
2248 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2249 return WINED3DERR_INVALIDCALL;
2252 switch(pLight->Type) {
2253 case WINED3DLIGHT_POINT:
2254 case WINED3DLIGHT_SPOT:
2255 case WINED3DLIGHT_PARALLELPOINT:
2256 case WINED3DLIGHT_GLSPOT:
2257 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2258 * most wanted
2260 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2262 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2263 return WINED3DERR_INVALIDCALL;
2265 break;
2267 case WINED3DLIGHT_DIRECTIONAL:
2268 /* Ignores attenuation */
2269 break;
2271 default:
2272 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2273 return WINED3DERR_INVALIDCALL;
2276 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2278 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2279 if(object->OriginalIndex == Index) break;
2280 object = NULL;
2283 if(!object) {
2284 TRACE("Adding new light\n");
2285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2286 if(!object) {
2287 ERR("Out of memory error when allocating a light\n");
2288 return E_OUTOFMEMORY;
2290 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2291 object->glIndex = -1;
2292 object->OriginalIndex = Index;
2295 /* Initialize the object */
2296 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,
2297 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2298 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2299 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2300 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2301 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2302 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2304 /* Save away the information */
2305 object->OriginalParms = *pLight;
2307 switch (pLight->Type) {
2308 case WINED3DLIGHT_POINT:
2309 /* Position */
2310 object->lightPosn[0] = pLight->Position.x;
2311 object->lightPosn[1] = pLight->Position.y;
2312 object->lightPosn[2] = pLight->Position.z;
2313 object->lightPosn[3] = 1.0f;
2314 object->cutoff = 180.0f;
2315 /* FIXME: Range */
2316 break;
2318 case WINED3DLIGHT_DIRECTIONAL:
2319 /* Direction */
2320 object->lightPosn[0] = -pLight->Direction.x;
2321 object->lightPosn[1] = -pLight->Direction.y;
2322 object->lightPosn[2] = -pLight->Direction.z;
2323 object->lightPosn[3] = 0.0f;
2324 object->exponent = 0.0f;
2325 object->cutoff = 180.0f;
2326 break;
2328 case WINED3DLIGHT_SPOT:
2329 /* Position */
2330 object->lightPosn[0] = pLight->Position.x;
2331 object->lightPosn[1] = pLight->Position.y;
2332 object->lightPosn[2] = pLight->Position.z;
2333 object->lightPosn[3] = 1.0f;
2335 /* Direction */
2336 object->lightDirn[0] = pLight->Direction.x;
2337 object->lightDirn[1] = pLight->Direction.y;
2338 object->lightDirn[2] = pLight->Direction.z;
2339 object->lightDirn[3] = 1.0f;
2342 * opengl-ish and d3d-ish spot lights use too different models for the
2343 * light "intensity" as a function of the angle towards the main light direction,
2344 * so we only can approximate very roughly.
2345 * however spot lights are rather rarely used in games (if ever used at all).
2346 * furthermore if still used, probably nobody pays attention to such details.
2348 if (pLight->Falloff == 0) {
2349 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2350 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2351 * will always be 1.0 for both of them, and we don't have to care for the
2352 * rest of the rather complex calculation
2354 object->exponent = 0.0f;
2355 } else {
2356 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2357 if (rho < 0.0001f) rho = 0.0001f;
2358 object->exponent = -0.3f/logf(cosf(rho/2));
2360 if (object->exponent > 128.0f)
2362 object->exponent = 128.0f;
2364 object->cutoff = pLight->Phi*90/M_PI;
2366 /* FIXME: Range */
2367 break;
2369 default:
2370 FIXME("Unrecognized light type %d\n", pLight->Type);
2373 /* Update the live definitions if the light is currently assigned a glIndex */
2374 if (object->glIndex != -1 && !This->isRecordingState) {
2375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2377 return WINED3D_OK;
2380 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2382 struct wined3d_light_info *lightInfo = NULL;
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2385 struct list *e;
2386 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2388 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2390 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2391 if(lightInfo->OriginalIndex == Index) break;
2392 lightInfo = NULL;
2395 if (lightInfo == NULL) {
2396 TRACE("Light information requested but light not defined\n");
2397 return WINED3DERR_INVALIDCALL;
2400 *pLight = lightInfo->OriginalParms;
2401 return WINED3D_OK;
2404 /*****
2405 * Get / Set Light Enable
2406 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2407 *****/
2408 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2410 struct wined3d_light_info *lightInfo = NULL;
2411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2412 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2413 struct list *e;
2414 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2416 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2418 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2419 if(lightInfo->OriginalIndex == Index) break;
2420 lightInfo = NULL;
2422 TRACE("Found light: %p\n", lightInfo);
2424 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2425 if (lightInfo == NULL) {
2427 TRACE("Light enabled requested but light not defined, so defining one!\n");
2428 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2430 /* Search for it again! Should be fairly quick as near head of list */
2431 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2433 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2434 if(lightInfo->OriginalIndex == Index) break;
2435 lightInfo = NULL;
2437 if (lightInfo == NULL) {
2438 FIXME("Adding default lights has failed dismally\n");
2439 return WINED3DERR_INVALIDCALL;
2443 if(!Enable) {
2444 if(lightInfo->glIndex != -1) {
2445 if(!This->isRecordingState) {
2446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2449 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2450 lightInfo->glIndex = -1;
2451 } else {
2452 TRACE("Light already disabled, nothing to do\n");
2454 lightInfo->enabled = FALSE;
2455 } else {
2456 lightInfo->enabled = TRUE;
2457 if (lightInfo->glIndex != -1) {
2458 /* nop */
2459 TRACE("Nothing to do as light was enabled\n");
2460 } else {
2461 int i;
2462 /* Find a free gl light */
2463 for(i = 0; i < This->maxConcurrentLights; i++) {
2464 if(This->updateStateBlock->activeLights[i] == NULL) {
2465 This->updateStateBlock->activeLights[i] = lightInfo;
2466 lightInfo->glIndex = i;
2467 break;
2470 if(lightInfo->glIndex == -1) {
2471 /* Our tests show that Windows returns D3D_OK in this situation, even with
2472 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2473 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2474 * as well for those lights.
2476 * TODO: Test how this affects rendering
2478 WARN("Too many concurrently active lights\n");
2479 return WINED3D_OK;
2482 /* i == lightInfo->glIndex */
2483 if(!This->isRecordingState) {
2484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2489 return WINED3D_OK;
2492 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2494 struct wined3d_light_info *lightInfo = NULL;
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 struct list *e;
2497 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2498 TRACE("(%p) : for idx(%d)\n", This, Index);
2500 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2502 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2503 if(lightInfo->OriginalIndex == Index) break;
2504 lightInfo = NULL;
2507 if (lightInfo == NULL) {
2508 TRACE("Light enabled state requested but light not defined\n");
2509 return WINED3DERR_INVALIDCALL;
2511 /* true is 128 according to SetLightEnable */
2512 *pEnable = lightInfo->enabled ? 128 : 0;
2513 return WINED3D_OK;
2516 /*****
2517 * Get / Set Clip Planes
2518 *****/
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2523 /* Validate Index */
2524 if (Index >= This->adapter->gl_info.limits.clipplanes)
2526 TRACE("Application has requested clipplane this device doesn't support\n");
2527 return WINED3DERR_INVALIDCALL;
2530 This->updateStateBlock->changed.clipplane |= 1 << Index;
2532 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2533 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2534 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2535 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2536 TRACE("Application is setting old values over, nothing to do\n");
2537 return WINED3D_OK;
2540 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2541 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2542 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2543 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2545 /* Handle recording of state blocks */
2546 if (This->isRecordingState) {
2547 TRACE("Recording... not performing anything\n");
2548 return WINED3D_OK;
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2553 return WINED3D_OK;
2556 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p) : for idx %d\n", This, Index);
2560 /* Validate Index */
2561 if (Index >= This->adapter->gl_info.limits.clipplanes)
2563 TRACE("Application has requested clipplane this device doesn't support\n");
2564 return WINED3DERR_INVALIDCALL;
2567 pPlane[0] = This->stateBlock->clipplane[Index][0];
2568 pPlane[1] = This->stateBlock->clipplane[Index][1];
2569 pPlane[2] = This->stateBlock->clipplane[Index][2];
2570 pPlane[3] = This->stateBlock->clipplane[Index][3];
2571 return WINED3D_OK;
2574 /*****
2575 * Get / Set Clip Plane Status
2576 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2577 *****/
2578 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 FIXME("(%p) : stub\n", This);
2581 if (NULL == pClipStatus) {
2582 return WINED3DERR_INVALIDCALL;
2584 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2585 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2586 return WINED3D_OK;
2589 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 FIXME("(%p) : stub\n", This);
2592 if (NULL == pClipStatus) {
2593 return WINED3DERR_INVALIDCALL;
2595 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2596 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2597 return WINED3D_OK;
2600 /*****
2601 * Get / Set Material
2602 *****/
2603 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 This->updateStateBlock->changed.material = TRUE;
2607 This->updateStateBlock->material = *pMaterial;
2609 /* Handle recording of state blocks */
2610 if (This->isRecordingState) {
2611 TRACE("Recording... not performing anything\n");
2612 return WINED3D_OK;
2615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2616 return WINED3D_OK;
2619 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 *pMaterial = This->updateStateBlock->material;
2622 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2623 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2624 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2625 pMaterial->Ambient.b, pMaterial->Ambient.a);
2626 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2627 pMaterial->Specular.b, pMaterial->Specular.a);
2628 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2629 pMaterial->Emissive.b, pMaterial->Emissive.a);
2630 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2632 return WINED3D_OK;
2635 /*****
2636 * Get / Set Indices
2637 *****/
2638 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2639 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 IWineD3DBuffer *oldIdxs;
2644 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2645 oldIdxs = This->updateStateBlock->pIndexData;
2647 This->updateStateBlock->changed.indices = TRUE;
2648 This->updateStateBlock->pIndexData = pIndexData;
2649 This->updateStateBlock->IndexFmt = fmt;
2651 /* Handle recording of state blocks */
2652 if (This->isRecordingState) {
2653 TRACE("Recording... not performing anything\n");
2654 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2655 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2656 return WINED3D_OK;
2659 if(oldIdxs != pIndexData) {
2660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2661 if(pIndexData) {
2662 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2663 IWineD3DBuffer_AddRef(pIndexData);
2665 if(oldIdxs) {
2666 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2667 IWineD3DBuffer_Release(oldIdxs);
2671 return WINED3D_OK;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 *ppIndexData = This->stateBlock->pIndexData;
2680 /* up ref count on ppindexdata */
2681 if (*ppIndexData) {
2682 IWineD3DBuffer_AddRef(*ppIndexData);
2683 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2684 }else{
2685 TRACE("(%p) No index data set\n", This);
2687 TRACE("Returning %p\n", *ppIndexData);
2689 return WINED3D_OK;
2692 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2693 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 TRACE("(%p)->(%d)\n", This, BaseIndex);
2697 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2698 TRACE("Application is setting the old value over, nothing to do\n");
2699 return WINED3D_OK;
2702 This->updateStateBlock->baseVertexIndex = BaseIndex;
2704 if (This->isRecordingState) {
2705 TRACE("Recording... not performing anything\n");
2706 return WINED3D_OK;
2708 /* The base vertex index affects the stream sources */
2709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2710 return WINED3D_OK;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 TRACE("(%p) : base_index %p\n", This, base_index);
2717 *base_index = This->stateBlock->baseVertexIndex;
2719 TRACE("Returning %u\n", *base_index);
2721 return WINED3D_OK;
2724 /*****
2725 * Get / Set Viewports
2726 *****/
2727 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2730 TRACE("(%p)\n", This);
2731 This->updateStateBlock->changed.viewport = TRUE;
2732 This->updateStateBlock->viewport = *pViewport;
2734 /* Handle recording of state blocks */
2735 if (This->isRecordingState) {
2736 TRACE("Recording... not performing anything\n");
2737 return WINED3D_OK;
2740 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2741 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2744 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p)\n", This);
2751 *pViewport = This->stateBlock->viewport;
2752 return WINED3D_OK;
2755 /*****
2756 * Get / Set Render States
2757 * TODO: Verify against dx9 definitions
2758 *****/
2759 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2762 DWORD oldValue = This->stateBlock->renderState[State];
2764 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2766 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2767 This->updateStateBlock->renderState[State] = Value;
2769 /* Handle recording of state blocks */
2770 if (This->isRecordingState) {
2771 TRACE("Recording... not performing anything\n");
2772 return WINED3D_OK;
2775 /* Compared here and not before the assignment to allow proper stateblock recording */
2776 if(Value == oldValue) {
2777 TRACE("Application is setting the old value over, nothing to do\n");
2778 } else {
2779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2782 return WINED3D_OK;
2785 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2788 *pValue = This->stateBlock->renderState[State];
2789 return WINED3D_OK;
2792 /*****
2793 * Get / Set Sampler States
2794 * TODO: Verify against dx9 definitions
2795 *****/
2797 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 DWORD oldValue;
2801 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2802 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2804 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2805 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2808 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2809 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2810 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2813 * SetSampler is designed to allow for more than the standard up to 8 textures
2814 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2815 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2817 * http://developer.nvidia.com/object/General_FAQ.html#t6
2819 * There are two new settings for GForce
2820 * the sampler one:
2821 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2822 * and the texture one:
2823 * GL_MAX_TEXTURE_COORDS_ARB.
2824 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2825 ******************/
2827 oldValue = This->stateBlock->samplerState[Sampler][Type];
2828 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2829 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2831 /* Handle recording of state blocks */
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2837 if(oldValue == Value) {
2838 TRACE("Application is setting the old value over, nothing to do\n");
2839 return WINED3D_OK;
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2844 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2851 This, Sampler, debug_d3dsamplerstate(Type), Type);
2853 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2854 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2857 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2858 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2859 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2861 *Value = This->stateBlock->samplerState[Sampler][Type];
2862 TRACE("(%p) : Returning %#x\n", This, *Value);
2864 return WINED3D_OK;
2867 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 This->updateStateBlock->changed.scissorRect = TRUE;
2871 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2872 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2873 return WINED3D_OK;
2875 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2877 if(This->isRecordingState) {
2878 TRACE("Recording... not performing anything\n");
2879 return WINED3D_OK;
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2884 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 *pRect = This->updateStateBlock->scissorRect;
2891 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2892 return WINED3D_OK;
2895 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2897 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2899 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2901 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2902 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2904 This->updateStateBlock->vertexDecl = pDecl;
2905 This->updateStateBlock->changed.vertexDecl = TRUE;
2907 if (This->isRecordingState) {
2908 TRACE("Recording... not performing anything\n");
2909 return WINED3D_OK;
2910 } else if(pDecl == oldDecl) {
2911 /* Checked after the assignment to allow proper stateblock recording */
2912 TRACE("Application is setting the old declaration over, nothing to do\n");
2913 return WINED3D_OK;
2916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2917 return WINED3D_OK;
2920 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2925 *ppDecl = This->stateBlock->vertexDecl;
2926 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2927 return WINED3D_OK;
2930 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2934 This->updateStateBlock->vertexShader = pShader;
2935 This->updateStateBlock->changed.vertexShader = TRUE;
2937 if (This->isRecordingState) {
2938 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2939 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2940 TRACE("Recording... not performing anything\n");
2941 return WINED3D_OK;
2942 } else if(oldShader == pShader) {
2943 /* Checked here to allow proper stateblock recording */
2944 TRACE("App is setting the old shader over, nothing to do\n");
2945 return WINED3D_OK;
2948 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2949 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2950 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2954 return WINED3D_OK;
2957 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 if (NULL == ppShader) {
2961 return WINED3DERR_INVALIDCALL;
2963 *ppShader = This->stateBlock->vertexShader;
2964 if( NULL != *ppShader)
2965 IWineD3DVertexShader_AddRef(*ppShader);
2967 TRACE("(%p) : returning %p\n", This, *ppShader);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2972 IWineD3DDevice *iface,
2973 UINT start,
2974 CONST BOOL *srcData,
2975 UINT count) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2978 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2980 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2981 iface, srcData, start, count);
2983 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2985 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2986 for (i = 0; i < cnt; i++)
2987 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2989 for (i = start; i < cnt + start; ++i) {
2990 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2993 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2999 IWineD3DDevice *iface,
3000 UINT start,
3001 BOOL *dstData,
3002 UINT count) {
3004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 int cnt = min(count, MAX_CONST_B - start);
3007 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3008 iface, dstData, start, count);
3010 if (dstData == NULL || cnt < 0)
3011 return WINED3DERR_INVALIDCALL;
3013 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3014 return WINED3D_OK;
3017 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3018 IWineD3DDevice *iface,
3019 UINT start,
3020 CONST int *srcData,
3021 UINT count) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3026 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3027 iface, srcData, start, count);
3029 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3031 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3032 for (i = 0; i < cnt; i++)
3033 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3034 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3036 for (i = start; i < cnt + start; ++i) {
3037 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3040 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3042 return WINED3D_OK;
3045 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3046 IWineD3DDevice *iface,
3047 UINT start,
3048 int *dstData,
3049 UINT count) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3052 int cnt = min(count, MAX_CONST_I - start);
3054 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3055 iface, dstData, start, count);
3057 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3058 return WINED3DERR_INVALIDCALL;
3060 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3061 return WINED3D_OK;
3064 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3065 IWineD3DDevice *iface,
3066 UINT start,
3067 CONST float *srcData,
3068 UINT count) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 UINT i;
3073 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3074 iface, srcData, start, count);
3076 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3077 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3078 return WINED3DERR_INVALIDCALL;
3080 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3081 if(TRACE_ON(d3d)) {
3082 for (i = 0; i < count; i++)
3083 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3084 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3087 if (!This->isRecordingState)
3089 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3093 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3094 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3100 IWineD3DDevice *iface,
3101 UINT start,
3102 float *dstData,
3103 UINT count) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 int cnt = min(count, This->d3d_vshader_constantF - start);
3108 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3109 iface, dstData, start, count);
3111 if (dstData == NULL || cnt < 0)
3112 return WINED3DERR_INVALIDCALL;
3114 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3115 return WINED3D_OK;
3118 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3119 DWORD i;
3120 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3126 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3128 DWORD i = This->rev_tex_unit_map[unit];
3129 DWORD j = This->texUnitMap[stage];
3131 This->texUnitMap[stage] = unit;
3132 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3134 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3137 This->rev_tex_unit_map[unit] = stage;
3138 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3140 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3144 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3145 int i;
3147 This->fixed_function_usage_map = 0;
3148 for (i = 0; i < MAX_TEXTURES; ++i) {
3149 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3150 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3151 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3152 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3153 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3154 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3155 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3156 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3158 if (color_op == WINED3DTOP_DISABLE) {
3159 /* Not used, and disable higher stages */
3160 break;
3163 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3164 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3165 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3166 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3167 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3168 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3169 This->fixed_function_usage_map |= (1 << i);
3172 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3173 This->fixed_function_usage_map |= (1 << (i + 1));
3178 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3180 unsigned int i, tex;
3181 WORD ffu_map;
3183 device_update_fixed_function_usage_map(This);
3184 ffu_map = This->fixed_function_usage_map;
3186 if (This->max_ffp_textures == gl_info->limits.texture_stages
3187 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3189 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3191 if (!(ffu_map & 1)) continue;
3193 if (This->texUnitMap[i] != i) {
3194 device_map_stage(This, i, i);
3195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3196 markTextureStagesDirty(This, i);
3199 return;
3202 /* Now work out the mapping */
3203 tex = 0;
3204 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3206 if (!(ffu_map & 1)) continue;
3208 if (This->texUnitMap[i] != tex) {
3209 device_map_stage(This, i, tex);
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3211 markTextureStagesDirty(This, i);
3214 ++tex;
3218 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3220 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3221 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3222 unsigned int i;
3224 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3225 if (sampler_type[i] && This->texUnitMap[i] != i)
3227 device_map_stage(This, i, i);
3228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3229 if (i < gl_info->limits.texture_stages)
3231 markTextureStagesDirty(This, i);
3237 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3238 const DWORD *vshader_sampler_tokens, DWORD unit)
3240 DWORD current_mapping = This->rev_tex_unit_map[unit];
3242 /* Not currently used */
3243 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3245 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3246 /* Used by a fragment sampler */
3248 if (!pshader_sampler_tokens) {
3249 /* No pixel shader, check fixed function */
3250 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3253 /* Pixel shader, check the shader's sampler map */
3254 return !pshader_sampler_tokens[current_mapping];
3257 /* Used by a vertex sampler */
3258 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3261 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3263 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3264 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3265 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3266 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3267 int i;
3269 if (ps) {
3270 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3272 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3273 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3274 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3277 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3278 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3279 if (vshader_sampler_type[i])
3281 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3283 /* Already mapped somewhere */
3284 continue;
3287 while (start >= 0) {
3288 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3290 device_map_stage(This, vsampler_idx, start);
3291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3293 --start;
3294 break;
3297 --start;
3303 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3305 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3306 BOOL vs = use_vs(This->stateBlock);
3307 BOOL ps = use_ps(This->stateBlock);
3309 * Rules are:
3310 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3311 * that would be really messy and require shader recompilation
3312 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3313 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3315 if (ps) device_map_psamplers(This, gl_info);
3316 else device_map_fixed_function_samplers(This, gl_info);
3318 if (vs) device_map_vsamplers(This, ps, gl_info);
3321 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3324 This->updateStateBlock->pixelShader = pShader;
3325 This->updateStateBlock->changed.pixelShader = TRUE;
3327 /* Handle recording of state blocks */
3328 if (This->isRecordingState) {
3329 TRACE("Recording... not performing anything\n");
3332 if (This->isRecordingState) {
3333 TRACE("Recording... not performing anything\n");
3334 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3335 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3336 return WINED3D_OK;
3339 if(pShader == oldShader) {
3340 TRACE("App is setting the old pixel shader over, nothing to do\n");
3341 return WINED3D_OK;
3344 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3345 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3347 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3350 return WINED3D_OK;
3353 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 if (NULL == ppShader) {
3357 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3358 return WINED3DERR_INVALIDCALL;
3361 *ppShader = This->stateBlock->pixelShader;
3362 if (NULL != *ppShader) {
3363 IWineD3DPixelShader_AddRef(*ppShader);
3365 TRACE("(%p) : returning %p\n", This, *ppShader);
3366 return WINED3D_OK;
3369 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3370 IWineD3DDevice *iface,
3371 UINT start,
3372 CONST BOOL *srcData,
3373 UINT count) {
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3378 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3379 iface, srcData, start, count);
3381 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3383 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3384 for (i = 0; i < cnt; i++)
3385 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3387 for (i = start; i < cnt + start; ++i) {
3388 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3391 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3393 return WINED3D_OK;
3396 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3397 IWineD3DDevice *iface,
3398 UINT start,
3399 BOOL *dstData,
3400 UINT count) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 int cnt = min(count, MAX_CONST_B - start);
3405 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3406 iface, dstData, start, count);
3408 if (dstData == NULL || cnt < 0)
3409 return WINED3DERR_INVALIDCALL;
3411 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3412 return WINED3D_OK;
3415 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3416 IWineD3DDevice *iface,
3417 UINT start,
3418 CONST int *srcData,
3419 UINT count) {
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3424 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3425 iface, srcData, start, count);
3427 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3429 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3430 for (i = 0; i < cnt; i++)
3431 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3432 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3434 for (i = start; i < cnt + start; ++i) {
3435 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3438 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3440 return WINED3D_OK;
3443 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3444 IWineD3DDevice *iface,
3445 UINT start,
3446 int *dstData,
3447 UINT count) {
3449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 int cnt = min(count, MAX_CONST_I - start);
3452 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3453 iface, dstData, start, count);
3455 if (dstData == NULL || cnt < 0)
3456 return WINED3DERR_INVALIDCALL;
3458 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3463 IWineD3DDevice *iface,
3464 UINT start,
3465 CONST float *srcData,
3466 UINT count) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 UINT i;
3471 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3472 iface, srcData, start, count);
3474 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3475 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3476 return WINED3DERR_INVALIDCALL;
3478 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3479 if(TRACE_ON(d3d)) {
3480 for (i = 0; i < count; i++)
3481 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3482 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3485 if (!This->isRecordingState)
3487 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3491 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3492 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3494 return WINED3D_OK;
3497 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3498 IWineD3DDevice *iface,
3499 UINT start,
3500 float *dstData,
3501 UINT count) {
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 int cnt = min(count, This->d3d_pshader_constantF - start);
3506 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3507 iface, dstData, start, count);
3509 if (dstData == NULL || cnt < 0)
3510 return WINED3DERR_INVALIDCALL;
3512 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3513 return WINED3D_OK;
3516 /* Context activation is done by the caller. */
3517 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3518 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3519 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3520 DWORD DestFVF)
3522 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3523 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3524 unsigned int i;
3525 WINED3DVIEWPORT vp;
3526 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3527 BOOL doClip;
3528 DWORD numTextures;
3530 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3532 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3535 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3537 ERR("Source has no position mask\n");
3538 return WINED3DERR_INVALIDCALL;
3541 /* We might access VBOs from this code, so hold the lock */
3542 ENTER_GL();
3544 if (dest->resource.allocatedMemory == NULL) {
3545 buffer_get_sysmem(dest);
3548 /* Get a pointer into the destination vbo(create one if none exists) and
3549 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3551 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3553 dest->flags |= WINED3D_BUFFER_CREATEBO;
3554 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3557 if (dest->buffer_object)
3559 unsigned char extrabytes = 0;
3560 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3561 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3562 * this may write 4 extra bytes beyond the area that should be written
3564 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3565 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3566 if(!dest_conv_addr) {
3567 ERR("Out of memory\n");
3568 /* Continue without storing converted vertices */
3570 dest_conv = dest_conv_addr;
3573 /* Should I clip?
3574 * a) WINED3DRS_CLIPPING is enabled
3575 * b) WINED3DVOP_CLIP is passed
3577 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3578 static BOOL warned = FALSE;
3580 * The clipping code is not quite correct. Some things need
3581 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3582 * so disable clipping for now.
3583 * (The graphics in Half-Life are broken, and my processvertices
3584 * test crashes with IDirect3DDevice3)
3585 doClip = TRUE;
3587 doClip = FALSE;
3588 if(!warned) {
3589 warned = TRUE;
3590 FIXME("Clipping is broken and disabled for now\n");
3592 } else doClip = FALSE;
3593 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3595 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3596 WINED3DTS_VIEW,
3597 &view_mat);
3598 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3599 WINED3DTS_PROJECTION,
3600 &proj_mat);
3601 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3602 WINED3DTS_WORLDMATRIX(0),
3603 &world_mat);
3605 TRACE("View mat:\n");
3606 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);
3607 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);
3608 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);
3609 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);
3611 TRACE("Proj mat:\n");
3612 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);
3613 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);
3614 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);
3615 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);
3617 TRACE("World mat:\n");
3618 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);
3619 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);
3620 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);
3621 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);
3623 /* Get the viewport */
3624 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3625 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3626 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3628 multiply_matrix(&mat,&view_mat,&world_mat);
3629 multiply_matrix(&mat,&proj_mat,&mat);
3631 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3633 for (i = 0; i < dwCount; i+= 1) {
3634 unsigned int tex_index;
3636 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3637 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3638 /* The position first */
3639 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3640 const float *p = (const float *)(element->data + i * element->stride);
3641 float x, y, z, rhw;
3642 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3644 /* Multiplication with world, view and projection matrix */
3645 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);
3646 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);
3647 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);
3648 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);
3650 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3652 /* WARNING: The following things are taken from d3d7 and were not yet checked
3653 * against d3d8 or d3d9!
3656 /* Clipping conditions: From msdn
3658 * A vertex is clipped if it does not match the following requirements
3659 * -rhw < x <= rhw
3660 * -rhw < y <= rhw
3661 * 0 < z <= rhw
3662 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3664 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3665 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3669 if( !doClip ||
3670 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3671 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3672 ( rhw > eps ) ) ) {
3674 /* "Normal" viewport transformation (not clipped)
3675 * 1) The values are divided by rhw
3676 * 2) The y axis is negative, so multiply it with -1
3677 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3678 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3679 * 4) Multiply x with Width/2 and add Width/2
3680 * 5) The same for the height
3681 * 6) Add the viewpoint X and Y to the 2D coordinates and
3682 * The minimum Z value to z
3683 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3685 * Well, basically it's simply a linear transformation into viewport
3686 * coordinates
3689 x /= rhw;
3690 y /= rhw;
3691 z /= rhw;
3693 y *= -1;
3695 x *= vp.Width / 2;
3696 y *= vp.Height / 2;
3697 z *= vp.MaxZ - vp.MinZ;
3699 x += vp.Width / 2 + vp.X;
3700 y += vp.Height / 2 + vp.Y;
3701 z += vp.MinZ;
3703 rhw = 1 / rhw;
3704 } else {
3705 /* That vertex got clipped
3706 * Contrary to OpenGL it is not dropped completely, it just
3707 * undergoes a different calculation.
3709 TRACE("Vertex got clipped\n");
3710 x += rhw;
3711 y += rhw;
3713 x /= 2;
3714 y /= 2;
3716 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3717 * outside of the main vertex buffer memory. That needs some more
3718 * investigation...
3722 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3725 ( (float *) dest_ptr)[0] = x;
3726 ( (float *) dest_ptr)[1] = y;
3727 ( (float *) dest_ptr)[2] = z;
3728 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3730 dest_ptr += 3 * sizeof(float);
3732 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3733 dest_ptr += sizeof(float);
3736 if(dest_conv) {
3737 float w = 1 / rhw;
3738 ( (float *) dest_conv)[0] = x * w;
3739 ( (float *) dest_conv)[1] = y * w;
3740 ( (float *) dest_conv)[2] = z * w;
3741 ( (float *) dest_conv)[3] = w;
3743 dest_conv += 3 * sizeof(float);
3745 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3746 dest_conv += sizeof(float);
3750 if (DestFVF & WINED3DFVF_PSIZE) {
3751 dest_ptr += sizeof(DWORD);
3752 if(dest_conv) dest_conv += sizeof(DWORD);
3754 if (DestFVF & WINED3DFVF_NORMAL) {
3755 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3756 const float *normal = (const float *)(element->data + i * element->stride);
3757 /* AFAIK this should go into the lighting information */
3758 FIXME("Didn't expect the destination to have a normal\n");
3759 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3760 if(dest_conv) {
3761 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3765 if (DestFVF & WINED3DFVF_DIFFUSE) {
3766 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3767 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3768 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3770 static BOOL warned = FALSE;
3772 if(!warned) {
3773 ERR("No diffuse color in source, but destination has one\n");
3774 warned = TRUE;
3777 *( (DWORD *) dest_ptr) = 0xffffffff;
3778 dest_ptr += sizeof(DWORD);
3780 if(dest_conv) {
3781 *( (DWORD *) dest_conv) = 0xffffffff;
3782 dest_conv += sizeof(DWORD);
3785 else {
3786 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3787 if(dest_conv) {
3788 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3789 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3790 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3791 dest_conv += sizeof(DWORD);
3796 if (DestFVF & WINED3DFVF_SPECULAR)
3798 /* What's the color value in the feedback buffer? */
3799 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3800 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3801 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3803 static BOOL warned = FALSE;
3805 if(!warned) {
3806 ERR("No specular color in source, but destination has one\n");
3807 warned = TRUE;
3810 *( (DWORD *) dest_ptr) = 0xFF000000;
3811 dest_ptr += sizeof(DWORD);
3813 if(dest_conv) {
3814 *( (DWORD *) dest_conv) = 0xFF000000;
3815 dest_conv += sizeof(DWORD);
3818 else {
3819 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3820 if(dest_conv) {
3821 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3822 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3823 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3824 dest_conv += sizeof(DWORD);
3829 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3830 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3831 const float *tex_coord = (const float *)(element->data + i * element->stride);
3832 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3834 ERR("No source texture, but destination requests one\n");
3835 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3836 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3838 else {
3839 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3840 if(dest_conv) {
3841 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3847 if(dest_conv) {
3848 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3849 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3850 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3851 dwCount * get_flexible_vertex_size(DestFVF),
3852 dest_conv_addr));
3853 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3854 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3857 LEAVE_GL();
3859 return WINED3D_OK;
3861 #undef copy_and_next
3863 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3864 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3865 DWORD DestFVF)
3867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3868 struct wined3d_stream_info stream_info;
3869 struct wined3d_context *context;
3870 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3871 HRESULT hr;
3873 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3875 if(pVertexDecl) {
3876 ERR("Output vertex declaration not implemented yet\n");
3879 /* Need any context to write to the vbo. */
3880 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3882 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3883 * control the streamIsUP flag, thus restore it afterwards.
3885 This->stateBlock->streamIsUP = FALSE;
3886 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3887 This->stateBlock->streamIsUP = streamWasUP;
3889 if(vbo || SrcStartIndex) {
3890 unsigned int i;
3891 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3892 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3894 * Also get the start index in, but only loop over all elements if there's something to add at all.
3896 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3898 struct wined3d_stream_info_element *e;
3900 if (!(stream_info.use_map & (1 << i))) continue;
3902 e = &stream_info.elements[i];
3903 if (e->buffer_object)
3905 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3906 e->buffer_object = 0;
3907 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3908 ENTER_GL();
3909 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3910 vb->buffer_object = 0;
3911 LEAVE_GL();
3913 if (e->data) e->data += e->stride * SrcStartIndex;
3917 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3918 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3920 context_release(context);
3922 return hr;
3925 /*****
3926 * Get / Set Texture Stage States
3927 * TODO: Verify against dx9 definitions
3928 *****/
3929 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3931 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3932 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3934 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3936 if (Stage >= gl_info->limits.texture_stages)
3938 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3939 Stage, gl_info->limits.texture_stages - 1);
3940 return WINED3D_OK;
3943 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3944 This->updateStateBlock->textureState[Stage][Type] = Value;
3946 if (This->isRecordingState) {
3947 TRACE("Recording... not performing anything\n");
3948 return WINED3D_OK;
3951 /* Checked after the assignments to allow proper stateblock recording */
3952 if(oldValue == Value) {
3953 TRACE("App is setting the old value over, nothing to do\n");
3954 return WINED3D_OK;
3957 if(Stage > This->stateBlock->lowest_disabled_stage &&
3958 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3959 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3960 * Changes in other states are important on disabled stages too
3962 return WINED3D_OK;
3965 if(Type == WINED3DTSS_COLOROP) {
3966 unsigned int i;
3968 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3969 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3970 * they have to be disabled
3972 * The current stage is dirtified below.
3974 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3975 TRACE("Additionally dirtifying stage %u\n", i);
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3978 This->stateBlock->lowest_disabled_stage = Stage;
3979 TRACE("New lowest disabled: %u\n", Stage);
3980 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3981 /* Previously disabled stage enabled. Stages above it may need enabling
3982 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3983 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3985 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3988 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3990 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3991 break;
3993 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3996 This->stateBlock->lowest_disabled_stage = i;
3997 TRACE("New lowest disabled: %u\n", i);
4001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4003 return WINED3D_OK;
4006 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4008 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4009 *pValue = This->updateStateBlock->textureState[Stage][Type];
4010 return WINED3D_OK;
4013 /*****
4014 * Get / Set Texture
4015 *****/
4016 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4017 DWORD stage, IWineD3DBaseTexture *texture)
4019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4020 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4021 IWineD3DBaseTexture *prev;
4023 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4025 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4026 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4028 /* Windows accepts overflowing this array... we do not. */
4029 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4031 WARN("Ignoring invalid stage %u.\n", stage);
4032 return WINED3D_OK;
4035 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4036 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4038 WARN("Rejecting attempt to set scratch texture.\n");
4039 return WINED3DERR_INVALIDCALL;
4042 This->updateStateBlock->changed.textures |= 1 << stage;
4044 prev = This->updateStateBlock->textures[stage];
4045 TRACE("Previous texture %p.\n", prev);
4047 if (texture == prev)
4049 TRACE("App is setting the same texture again, nothing to do.\n");
4050 return WINED3D_OK;
4053 TRACE("Setting new texture to %p.\n", texture);
4054 This->updateStateBlock->textures[stage] = texture;
4056 if (This->isRecordingState)
4058 TRACE("Recording... not performing anything\n");
4060 if (texture) IWineD3DBaseTexture_AddRef(texture);
4061 if (prev) IWineD3DBaseTexture_Release(prev);
4063 return WINED3D_OK;
4066 if (texture)
4068 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4069 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4070 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4072 IWineD3DBaseTexture_AddRef(texture);
4074 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4079 if (!prev && stage < gl_info->limits.texture_stages)
4081 /* The source arguments for color and alpha ops have different
4082 * meanings when a NULL texture is bound, so the COLOROP and
4083 * ALPHAOP have to be dirtified. */
4084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4088 if (bind_count == 1) t->baseTexture.sampler = stage;
4091 if (prev)
4093 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4094 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4096 IWineD3DBaseTexture_Release(prev);
4098 if (!texture && stage < gl_info->limits.texture_stages)
4100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4104 if (bind_count && t->baseTexture.sampler == stage)
4106 unsigned int i;
4108 /* Search for other stages the texture is bound to. Shouldn't
4109 * happen if applications bind textures to a single stage only. */
4110 TRACE("Searching for other stages the texture is bound to.\n");
4111 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4113 if (This->updateStateBlock->textures[i] == prev)
4115 TRACE("Texture is also bound to stage %u.\n", i);
4116 t->baseTexture.sampler = i;
4117 break;
4123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4125 return WINED3D_OK;
4128 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4131 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4133 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4134 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4137 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4138 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4139 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4142 *ppTexture=This->stateBlock->textures[Stage];
4143 if (*ppTexture)
4144 IWineD3DBaseTexture_AddRef(*ppTexture);
4146 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4148 return WINED3D_OK;
4151 /*****
4152 * Get Back Buffer
4153 *****/
4154 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4155 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4157 IWineD3DSwapChain *swapchain;
4158 HRESULT hr;
4160 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4161 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4163 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4164 if (FAILED(hr))
4166 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4167 return hr;
4170 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4171 IWineD3DSwapChain_Release(swapchain);
4172 if (FAILED(hr))
4174 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4175 return hr;
4178 return WINED3D_OK;
4181 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4183 WARN("(%p) : stub, calling idirect3d for now\n", This);
4184 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4187 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4189 IWineD3DSwapChain *swapChain;
4190 HRESULT hr;
4192 if(iSwapChain > 0) {
4193 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4194 if (hr == WINED3D_OK) {
4195 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4196 IWineD3DSwapChain_Release(swapChain);
4197 } else {
4198 FIXME("(%p) Error getting display mode\n", This);
4200 } else {
4201 /* Don't read the real display mode,
4202 but return the stored mode instead. X11 can't change the color
4203 depth, and some apps are pretty angry if they SetDisplayMode from
4204 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4206 Also don't relay to the swapchain because with ddraw it's possible
4207 that there isn't a swapchain at all */
4208 pMode->Width = This->ddraw_width;
4209 pMode->Height = This->ddraw_height;
4210 pMode->Format = This->ddraw_format;
4211 pMode->RefreshRate = 0;
4212 hr = WINED3D_OK;
4215 return hr;
4218 /*****
4219 * Stateblock related functions
4220 *****/
4222 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4224 IWineD3DStateBlock *stateblock;
4225 HRESULT hr;
4227 TRACE("(%p)\n", This);
4229 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4231 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4232 if (FAILED(hr)) return hr;
4234 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4235 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4236 This->isRecordingState = TRUE;
4238 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4240 return WINED3D_OK;
4243 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4245 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4247 if (!This->isRecordingState) {
4248 WARN("(%p) not recording! returning error\n", This);
4249 *ppStateBlock = NULL;
4250 return WINED3DERR_INVALIDCALL;
4253 stateblock_init_contained_states(object);
4255 *ppStateBlock = (IWineD3DStateBlock*) object;
4256 This->isRecordingState = FALSE;
4257 This->updateStateBlock = This->stateBlock;
4258 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4259 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4260 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4261 return WINED3D_OK;
4264 /*****
4265 * Scene related functions
4266 *****/
4267 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4268 /* At the moment we have no need for any functionality at the beginning
4269 of a scene */
4270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4271 TRACE("(%p)\n", This);
4273 if(This->inScene) {
4274 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4275 return WINED3DERR_INVALIDCALL;
4277 This->inScene = TRUE;
4278 return WINED3D_OK;
4281 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4284 struct wined3d_context *context;
4286 TRACE("(%p)\n", This);
4288 if(!This->inScene) {
4289 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4290 return WINED3DERR_INVALIDCALL;
4293 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4294 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4295 wglFlush();
4296 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4297 * fails. */
4298 context_release(context);
4300 This->inScene = FALSE;
4301 return WINED3D_OK;
4304 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4305 const RECT *pSourceRect, const RECT *pDestRect,
4306 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4308 IWineD3DSwapChain *swapChain = NULL;
4309 int i;
4310 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4312 TRACE("iface %p.\n", iface);
4314 for(i = 0 ; i < swapchains ; i ++) {
4316 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4317 TRACE("presentinng chain %d, %p\n", i, swapChain);
4318 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4319 IWineD3DSwapChain_Release(swapChain);
4322 return WINED3D_OK;
4325 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4326 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4328 /* partial viewport*/
4329 if (viewport->X != 0 || viewport->Y != 0
4330 || viewport->Width < target->currentDesc.Width
4331 || viewport->Height < target->currentDesc.Height)
4332 return FALSE;
4334 /* partial scissor rect */
4335 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4336 || scissor_rect->right < target->currentDesc.Width
4337 || scissor_rect->bottom < target->currentDesc.Height))
4338 return FALSE;
4340 /* partial clear rect */
4341 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4342 || clear_rect->x2 < target->currentDesc.Width
4343 || clear_rect->y2 < target->currentDesc.Height))
4344 return FALSE;
4346 return TRUE;
4349 /* Not called from the VTable (internal subroutine) */
4350 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4351 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4353 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4354 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4355 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4356 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4357 GLbitfield glMask = 0;
4358 unsigned int i;
4359 WINED3DRECT curRect;
4360 RECT vp_rect;
4361 UINT drawable_width, drawable_height;
4362 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4363 struct wined3d_context *context;
4365 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4366 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4367 * for the cleared parts, and the untouched parts.
4369 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4370 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4371 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4372 * checking all this if the dest surface is in the drawable anyway.
4374 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4376 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4377 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4380 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4381 if (!context->valid)
4383 context_release(context);
4384 WARN("Invalid context, skipping clear.\n");
4385 return WINED3D_OK;
4388 target->get_drawable_size(context, &drawable_width, &drawable_height);
4390 ENTER_GL();
4392 /* Only set the values up once, as they are not changing */
4393 if (Flags & WINED3DCLEAR_STENCIL) {
4394 glClearStencil(Stencil);
4395 checkGLcall("glClearStencil");
4396 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4397 glStencilMask(0xFFFFFFFF);
4400 if (Flags & WINED3DCLEAR_ZBUFFER) {
4401 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4402 glDepthMask(GL_TRUE);
4403 glClearDepth(Z);
4404 checkGLcall("glClearDepth");
4405 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4408 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4409 surface_load_ds_location(This->stencilBufferTarget, context, location);
4412 if (Flags & WINED3DCLEAR_TARGET) {
4413 TRACE("Clearing screen with glClear to color %x\n", Color);
4414 glClearColor(D3DCOLOR_R(Color),
4415 D3DCOLOR_G(Color),
4416 D3DCOLOR_B(Color),
4417 D3DCOLOR_A(Color));
4418 checkGLcall("glClearColor");
4420 /* Clear ALL colors! */
4421 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4422 glMask = glMask | GL_COLOR_BUFFER_BIT;
4425 vp_rect.left = vp->X;
4426 vp_rect.top = vp->Y;
4427 vp_rect.right = vp->X + vp->Width;
4428 vp_rect.bottom = vp->Y + vp->Height;
4429 if (!(Count > 0 && pRects)) {
4430 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4431 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4433 if (context->render_offscreen)
4435 glScissor(vp_rect.left, vp_rect.top,
4436 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4437 } else {
4438 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4439 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4441 checkGLcall("glScissor");
4442 glClear(glMask);
4443 checkGLcall("glClear");
4444 } else {
4445 /* Now process each rect in turn */
4446 for (i = 0; i < Count; i++) {
4447 /* Note gl uses lower left, width/height */
4448 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4449 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4450 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4452 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4453 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4454 curRect.x1, (target->currentDesc.Height - curRect.y2),
4455 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4457 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4458 * The rectangle is not cleared, no error is returned, but further rectanlges are
4459 * still cleared if they are valid
4461 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4462 TRACE("Rectangle with negative dimensions, ignoring\n");
4463 continue;
4466 if (context->render_offscreen)
4468 glScissor(curRect.x1, curRect.y1,
4469 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4470 } else {
4471 glScissor(curRect.x1, drawable_height - curRect.y2,
4472 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4474 checkGLcall("glScissor");
4476 glClear(glMask);
4477 checkGLcall("glClear");
4481 /* Restore the old values (why..?) */
4482 if (Flags & WINED3DCLEAR_STENCIL) {
4483 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4485 if (Flags & WINED3DCLEAR_TARGET) {
4486 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4487 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4488 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4489 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4490 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4492 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4493 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4495 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4497 if (Flags & WINED3DCLEAR_ZBUFFER) {
4498 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4499 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4500 surface_modify_ds_location(This->stencilBufferTarget, location);
4503 LEAVE_GL();
4505 wglFlush(); /* Flush to ensure ordering across contexts. */
4507 context_release(context);
4509 return WINED3D_OK;
4512 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4513 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4517 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4518 Count, pRects, Flags, Color, Z, Stencil);
4520 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4521 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4522 /* TODO: What about depth stencil buffers without stencil bits? */
4523 return WINED3DERR_INVALIDCALL;
4526 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4529 /*****
4530 * Drawing functions
4531 *****/
4533 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4534 WINED3DPRIMITIVETYPE primitive_type)
4536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4540 This->updateStateBlock->changed.primitive_type = TRUE;
4541 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4544 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4545 WINED3DPRIMITIVETYPE *primitive_type)
4547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4549 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4551 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4553 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4556 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4562 if(!This->stateBlock->vertexDecl) {
4563 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4564 return WINED3DERR_INVALIDCALL;
4567 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4568 if(This->stateBlock->streamIsUP) {
4569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4570 This->stateBlock->streamIsUP = FALSE;
4573 if(This->stateBlock->loadBaseVertexIndex != 0) {
4574 This->stateBlock->loadBaseVertexIndex = 0;
4575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4577 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4578 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4579 return WINED3D_OK;
4582 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4585 UINT idxStride = 2;
4586 IWineD3DBuffer *pIB;
4587 GLuint vbo;
4589 pIB = This->stateBlock->pIndexData;
4590 if (!pIB) {
4591 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4592 * without an index buffer set. (The first time at least...)
4593 * D3D8 simply dies, but I doubt it can do much harm to return
4594 * D3DERR_INVALIDCALL there as well. */
4595 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4596 return WINED3DERR_INVALIDCALL;
4599 if(!This->stateBlock->vertexDecl) {
4600 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4601 return WINED3DERR_INVALIDCALL;
4604 if(This->stateBlock->streamIsUP) {
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4606 This->stateBlock->streamIsUP = FALSE;
4608 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4610 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4612 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4613 idxStride = 2;
4614 } else {
4615 idxStride = 4;
4618 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4619 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4623 drawPrimitive(iface, index_count, startIndex, idxStride,
4624 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4626 return WINED3D_OK;
4629 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4630 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 IWineD3DBuffer *vb;
4635 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4636 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4638 if(!This->stateBlock->vertexDecl) {
4639 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4640 return WINED3DERR_INVALIDCALL;
4643 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4644 vb = This->stateBlock->streamSource[0];
4645 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4646 if (vb) IWineD3DBuffer_Release(vb);
4647 This->stateBlock->streamOffset[0] = 0;
4648 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4649 This->stateBlock->streamIsUP = TRUE;
4650 This->stateBlock->loadBaseVertexIndex = 0;
4652 /* TODO: Only mark dirty if drawing from a different UP address */
4653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4655 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4657 /* MSDN specifies stream zero settings must be set to NULL */
4658 This->stateBlock->streamStride[0] = 0;
4659 This->stateBlock->streamSource[0] = NULL;
4661 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4662 * the new stream sources or use UP drawing again
4664 return WINED3D_OK;
4667 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4668 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4669 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4671 int idxStride;
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 IWineD3DBuffer *vb;
4674 IWineD3DBuffer *ib;
4676 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4677 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4679 if(!This->stateBlock->vertexDecl) {
4680 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4681 return WINED3DERR_INVALIDCALL;
4684 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4685 idxStride = 2;
4686 } else {
4687 idxStride = 4;
4690 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4691 vb = This->stateBlock->streamSource[0];
4692 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4693 if (vb) IWineD3DBuffer_Release(vb);
4694 This->stateBlock->streamIsUP = TRUE;
4695 This->stateBlock->streamOffset[0] = 0;
4696 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4698 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4699 This->stateBlock->baseVertexIndex = 0;
4700 This->stateBlock->loadBaseVertexIndex = 0;
4701 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4705 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4707 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4708 This->stateBlock->streamSource[0] = NULL;
4709 This->stateBlock->streamStride[0] = 0;
4710 ib = This->stateBlock->pIndexData;
4711 if(ib) {
4712 IWineD3DBuffer_Release(ib);
4713 This->stateBlock->pIndexData = NULL;
4715 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4716 * SetStreamSource to specify a vertex buffer
4719 return WINED3D_OK;
4722 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4723 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4727 /* Mark the state dirty until we have nicer tracking
4728 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4729 * that value.
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4733 This->stateBlock->baseVertexIndex = 0;
4734 This->up_strided = DrawPrimStrideData;
4735 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4736 This->up_strided = NULL;
4737 return WINED3D_OK;
4740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4741 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4742 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4745 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4747 /* Mark the state dirty until we have nicer tracking
4748 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4749 * that value.
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4753 This->stateBlock->streamIsUP = TRUE;
4754 This->stateBlock->baseVertexIndex = 0;
4755 This->up_strided = DrawPrimStrideData;
4756 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4757 This->up_strided = NULL;
4758 return WINED3D_OK;
4761 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4762 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4763 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4765 WINED3DLOCKED_BOX src;
4766 WINED3DLOCKED_BOX dst;
4767 HRESULT hr;
4769 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4770 iface, pSourceVolume, pDestinationVolume);
4772 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4773 * dirtification to improve loading performance.
4775 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4776 if(FAILED(hr)) return hr;
4777 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4778 if(FAILED(hr)) {
4779 IWineD3DVolume_UnlockBox(pSourceVolume);
4780 return hr;
4783 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4785 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4786 if(FAILED(hr)) {
4787 IWineD3DVolume_UnlockBox(pSourceVolume);
4788 } else {
4789 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4791 return hr;
4794 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4795 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4797 unsigned int level_count, i;
4798 WINED3DRESOURCETYPE type;
4799 HRESULT hr;
4801 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4803 /* Verify that the source and destination textures are non-NULL. */
4804 if (!src_texture || !dst_texture)
4806 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4807 return WINED3DERR_INVALIDCALL;
4810 if (src_texture == dst_texture)
4812 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4813 return WINED3DERR_INVALIDCALL;
4816 /* Verify that the source and destination textures are the same type. */
4817 type = IWineD3DBaseTexture_GetType(src_texture);
4818 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4820 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4821 return WINED3DERR_INVALIDCALL;
4824 /* Check that both textures have the identical numbers of levels. */
4825 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4826 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4828 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4829 return WINED3DERR_INVALIDCALL;
4832 /* Make sure that the destination texture is loaded. */
4833 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4835 /* Update every surface level of the texture. */
4836 switch (type)
4838 case WINED3DRTYPE_TEXTURE:
4840 IWineD3DSurface *src_surface;
4841 IWineD3DSurface *dst_surface;
4843 for (i = 0; i < level_count; ++i)
4845 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4846 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4847 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4848 IWineD3DSurface_Release(dst_surface);
4849 IWineD3DSurface_Release(src_surface);
4850 if (FAILED(hr))
4852 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4853 return hr;
4856 break;
4859 case WINED3DRTYPE_CUBETEXTURE:
4861 IWineD3DSurface *src_surface;
4862 IWineD3DSurface *dst_surface;
4863 WINED3DCUBEMAP_FACES face;
4865 for (i = 0; i < level_count; ++i)
4867 /* Update each cube face. */
4868 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4870 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4871 face, i, &src_surface);
4872 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4873 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4874 face, i, &dst_surface);
4875 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4876 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4877 IWineD3DSurface_Release(dst_surface);
4878 IWineD3DSurface_Release(src_surface);
4879 if (FAILED(hr))
4881 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4882 return hr;
4886 break;
4889 case WINED3DRTYPE_VOLUMETEXTURE:
4891 IWineD3DVolume *src_volume;
4892 IWineD3DVolume *dst_volume;
4894 for (i = 0; i < level_count; ++i)
4896 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4897 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4898 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4899 IWineD3DVolume_Release(dst_volume);
4900 IWineD3DVolume_Release(src_volume);
4901 if (FAILED(hr))
4903 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4904 return hr;
4907 break;
4910 default:
4911 FIXME("Unsupported texture type %#x.\n", type);
4912 return WINED3DERR_INVALIDCALL;
4915 return WINED3D_OK;
4918 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4919 IWineD3DSwapChain *swapChain;
4920 HRESULT hr;
4921 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4922 if(hr == WINED3D_OK) {
4923 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4924 IWineD3DSwapChain_Release(swapChain);
4926 return hr;
4929 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 IWineD3DBaseTextureImpl *texture;
4932 DWORD i;
4934 TRACE("(%p) : %p\n", This, pNumPasses);
4936 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4937 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4938 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4939 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4941 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4942 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4943 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4946 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4947 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4949 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4950 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4951 return E_FAIL;
4953 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4954 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4955 return E_FAIL;
4957 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4958 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4959 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4960 return E_FAIL;
4964 /* return a sensible default */
4965 *pNumPasses = 1;
4967 TRACE("returning D3D_OK\n");
4968 return WINED3D_OK;
4971 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4973 int i;
4975 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4977 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4978 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4979 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4981 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4986 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 int j;
4989 UINT NewSize;
4990 PALETTEENTRY **palettes;
4992 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4994 if (PaletteNumber >= MAX_PALETTES) {
4995 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4996 return WINED3DERR_INVALIDCALL;
4999 if (PaletteNumber >= This->NumberOfPalettes) {
5000 NewSize = This->NumberOfPalettes;
5001 do {
5002 NewSize *= 2;
5003 } while(PaletteNumber >= NewSize);
5004 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5005 if (!palettes) {
5006 ERR("Out of memory!\n");
5007 return E_OUTOFMEMORY;
5009 This->palettes = palettes;
5010 This->NumberOfPalettes = NewSize;
5013 if (!This->palettes[PaletteNumber]) {
5014 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5015 if (!This->palettes[PaletteNumber]) {
5016 ERR("Out of memory!\n");
5017 return E_OUTOFMEMORY;
5021 for (j = 0; j < 256; ++j) {
5022 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5023 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5024 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5025 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5027 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5028 TRACE("(%p) : returning\n", This);
5029 return WINED3D_OK;
5032 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5034 int j;
5035 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5036 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5037 /* What happens in such situation isn't documented; Native seems to silently abort
5038 on such conditions. Return Invalid Call. */
5039 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5040 return WINED3DERR_INVALIDCALL;
5042 for (j = 0; j < 256; ++j) {
5043 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5044 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5045 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5046 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5048 TRACE("(%p) : returning\n", This);
5049 return WINED3D_OK;
5052 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5054 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5055 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5056 (tested with reference rasterizer). Return Invalid Call. */
5057 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5058 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5059 return WINED3DERR_INVALIDCALL;
5061 /*TODO: stateblocks */
5062 if (This->currentPalette != PaletteNumber) {
5063 This->currentPalette = PaletteNumber;
5064 dirtify_p8_texture_samplers(This);
5066 TRACE("(%p) : returning\n", This);
5067 return WINED3D_OK;
5070 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 if (PaletteNumber == NULL) {
5073 WARN("(%p) : returning Invalid Call\n", This);
5074 return WINED3DERR_INVALIDCALL;
5076 /*TODO: stateblocks */
5077 *PaletteNumber = This->currentPalette;
5078 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5079 return WINED3D_OK;
5082 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5084 static BOOL warned;
5085 if (!warned)
5087 FIXME("(%p) : stub\n", This);
5088 warned = TRUE;
5091 This->softwareVertexProcessing = bSoftware;
5092 return WINED3D_OK;
5096 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5098 static BOOL warned;
5099 if (!warned)
5101 FIXME("(%p) : stub\n", This);
5102 warned = TRUE;
5104 return This->softwareVertexProcessing;
5107 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5108 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5110 IWineD3DSwapChain *swapchain;
5111 HRESULT hr;
5113 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5114 iface, swapchain_idx, raster_status);
5116 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5117 if (FAILED(hr))
5119 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5120 return hr;
5123 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5124 IWineD3DSwapChain_Release(swapchain);
5125 if (FAILED(hr))
5127 WARN("Failed to get raster status, hr %#x.\n", hr);
5128 return hr;
5131 return WINED3D_OK;
5134 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5136 static BOOL warned;
5137 if(nSegments != 0.0f) {
5138 if (!warned)
5140 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5141 warned = TRUE;
5144 return WINED3D_OK;
5147 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5149 static BOOL warned;
5150 if (!warned)
5152 FIXME("iface %p stub!\n", iface);
5153 warned = TRUE;
5155 return 0.0f;
5158 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5159 const struct wined3d_format_desc *src_format_desc, *dst_format_desc;
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5161 /** TODO: remove casts to IWineD3DSurfaceImpl
5162 * NOTE: move code to surface to accomplish this
5163 ****************************************/
5164 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5165 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5166 int srcWidth, srcHeight;
5167 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5168 WINED3DFORMAT destFormat, srcFormat;
5169 UINT destSize;
5170 int srcLeft, destLeft, destTop;
5171 WINED3DPOOL srcPool, destPool;
5172 int offset = 0;
5173 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5174 GLenum dummy;
5175 DWORD sampler;
5176 int bpp;
5177 CONVERT_TYPES convert = NO_CONVERSION;
5178 struct wined3d_context *context;
5180 WINED3DSURFACE_DESC winedesc;
5182 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5184 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5185 srcSurfaceWidth = winedesc.width;
5186 srcSurfaceHeight = winedesc.height;
5187 srcPool = winedesc.pool;
5188 srcFormat = winedesc.format;
5190 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5191 destSurfaceWidth = winedesc.width;
5192 destSurfaceHeight = winedesc.height;
5193 destPool = winedesc.pool;
5194 destFormat = winedesc.format;
5195 destSize = winedesc.size;
5197 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5198 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5199 return WINED3DERR_INVALIDCALL;
5202 /* This call loads the opengl surface directly, instead of copying the surface to the
5203 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5204 * copy in sysmem and use regular surface loading.
5206 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5207 if(convert != NO_CONVERSION) {
5208 return IWineD3DSurface_BltFast(pDestinationSurface,
5209 pDestPoint ? pDestPoint->x : 0,
5210 pDestPoint ? pDestPoint->y : 0,
5211 pSourceSurface, pSourceRect, 0);
5214 if (destFormat == WINED3DFMT_UNKNOWN) {
5215 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5216 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5218 /* Get the update surface description */
5219 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5222 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5224 ENTER_GL();
5225 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5226 checkGLcall("glActiveTextureARB");
5227 LEAVE_GL();
5229 /* Make sure the surface is loaded and up to date */
5230 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5231 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5233 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5234 dst_format_desc = dst_impl->resource.format_desc;
5236 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5237 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5238 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5239 srcLeft = pSourceRect ? pSourceRect->left : 0;
5240 destLeft = pDestPoint ? pDestPoint->x : 0;
5241 destTop = pDestPoint ? pDestPoint->y : 0;
5244 /* This function doesn't support compressed textures
5245 the pitch is just bytesPerPixel * width */
5246 if(srcWidth != srcSurfaceWidth || srcLeft ){
5247 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5248 offset += srcLeft * src_format_desc->byte_count;
5249 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5251 /* TODO DXT formats */
5253 if(pSourceRect != NULL && pSourceRect->top != 0){
5254 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5256 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5257 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5258 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5260 /* Sanity check */
5261 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5263 /* need to lock the surface to get the data */
5264 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5267 ENTER_GL();
5269 /* TODO: Cube and volume support */
5270 if(rowoffset != 0){
5271 /* not a whole row so we have to do it a line at a time */
5272 int j;
5274 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5275 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5277 for (j = destTop; j < (srcHeight + destTop); ++j)
5279 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5280 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5281 data += rowoffset;
5284 } else { /* Full width, so just write out the whole texture */
5285 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5287 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5289 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5291 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5292 FIXME("Updating part of a compressed texture is not supported.\n");
5294 if (destFormat != srcFormat)
5296 FIXME("Updating mixed format compressed textures is not supported.\n");
5298 else
5300 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5301 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5304 else
5306 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5307 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5310 checkGLcall("glTexSubImage2D");
5312 LEAVE_GL();
5313 context_release(context);
5315 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5316 sampler = This->rev_tex_unit_map[0];
5317 if (sampler != WINED3D_UNMAPPED_STAGE)
5319 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5322 return WINED3D_OK;
5325 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5327 struct WineD3DRectPatch *patch;
5328 GLenum old_primitive_type;
5329 unsigned int i;
5330 struct list *e;
5331 BOOL found;
5332 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5334 if(!(Handle || pRectPatchInfo)) {
5335 /* TODO: Write a test for the return value, thus the FIXME */
5336 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5337 return WINED3DERR_INVALIDCALL;
5340 if(Handle) {
5341 i = PATCHMAP_HASHFUNC(Handle);
5342 found = FALSE;
5343 LIST_FOR_EACH(e, &This->patches[i]) {
5344 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5345 if(patch->Handle == Handle) {
5346 found = TRUE;
5347 break;
5351 if(!found) {
5352 TRACE("Patch does not exist. Creating a new one\n");
5353 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5354 patch->Handle = Handle;
5355 list_add_head(&This->patches[i], &patch->entry);
5356 } else {
5357 TRACE("Found existing patch %p\n", patch);
5359 } else {
5360 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5361 * attributes we have to tesselate, read back, and draw. This needs a patch
5362 * management structure instance. Create one.
5364 * A possible improvement is to check if a vertex shader is used, and if not directly
5365 * draw the patch.
5367 FIXME("Drawing an uncached patch. This is slow\n");
5368 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5371 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5372 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5373 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5374 HRESULT hr;
5375 TRACE("Tesselation density or patch info changed, retesselating\n");
5377 if(pRectPatchInfo) {
5378 patch->RectPatchInfo = *pRectPatchInfo;
5380 patch->numSegs[0] = pNumSegs[0];
5381 patch->numSegs[1] = pNumSegs[1];
5382 patch->numSegs[2] = pNumSegs[2];
5383 patch->numSegs[3] = pNumSegs[3];
5385 hr = tesselate_rectpatch(This, patch);
5386 if(FAILED(hr)) {
5387 WARN("Patch tesselation failed\n");
5389 /* Do not release the handle to store the params of the patch */
5390 if(!Handle) {
5391 HeapFree(GetProcessHeap(), 0, patch);
5393 return hr;
5397 This->currentPatch = patch;
5398 old_primitive_type = This->stateBlock->gl_primitive_type;
5399 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5400 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5401 This->stateBlock->gl_primitive_type = old_primitive_type;
5402 This->currentPatch = NULL;
5404 /* Destroy uncached patches */
5405 if(!Handle) {
5406 HeapFree(GetProcessHeap(), 0, patch->mem);
5407 HeapFree(GetProcessHeap(), 0, patch);
5409 return WINED3D_OK;
5412 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5413 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5415 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5416 iface, handle, segment_count, patch_info);
5418 return WINED3D_OK;
5421 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5423 int i;
5424 struct WineD3DRectPatch *patch;
5425 struct list *e;
5426 TRACE("(%p) Handle(%d)\n", This, Handle);
5428 i = PATCHMAP_HASHFUNC(Handle);
5429 LIST_FOR_EACH(e, &This->patches[i]) {
5430 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5431 if(patch->Handle == Handle) {
5432 TRACE("Deleting patch %p\n", patch);
5433 list_remove(&patch->entry);
5434 HeapFree(GetProcessHeap(), 0, patch->mem);
5435 HeapFree(GetProcessHeap(), 0, patch);
5436 return WINED3D_OK;
5440 /* TODO: Write a test for the return value */
5441 FIXME("Attempt to destroy nonexistent patch\n");
5442 return WINED3DERR_INVALIDCALL;
5445 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5446 const WINED3DRECT *rect, const float color[4])
5448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5449 struct wined3d_context *context;
5451 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5452 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5454 if (!surface_is_offscreen(surface))
5456 TRACE("Surface %p is onscreen\n", surface);
5458 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5459 ENTER_GL();
5460 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5461 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5463 else
5465 TRACE("Surface %p is offscreen\n", surface);
5467 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5468 ENTER_GL();
5469 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5470 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5471 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5474 if (rect) {
5475 glEnable(GL_SCISSOR_TEST);
5476 if(surface_is_offscreen(surface)) {
5477 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5478 } else {
5479 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5480 rect->x2 - rect->x1, rect->y2 - rect->y1);
5482 checkGLcall("glScissor");
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5484 } else {
5485 glDisable(GL_SCISSOR_TEST);
5487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5489 glDisable(GL_BLEND);
5490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5492 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5495 glClearColor(color[0], color[1], color[2], color[3]);
5496 glClear(GL_COLOR_BUFFER_BIT);
5497 checkGLcall("glClear");
5499 LEAVE_GL();
5501 wglFlush(); /* Flush to ensure ordering across contexts. */
5503 context_release(context);
5506 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5507 unsigned int r, g, b, a;
5508 DWORD ret;
5510 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5511 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5512 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5513 return color;
5515 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5517 a = (color & 0xff000000) >> 24;
5518 r = (color & 0x00ff0000) >> 16;
5519 g = (color & 0x0000ff00) >> 8;
5520 b = (color & 0x000000ff) >> 0;
5522 switch(destfmt)
5524 case WINED3DFMT_B5G6R5_UNORM:
5525 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5526 r = (r * 32) / 256;
5527 g = (g * 64) / 256;
5528 b = (b * 32) / 256;
5529 ret = r << 11;
5530 ret |= g << 5;
5531 ret |= b;
5532 TRACE("Returning %08x\n", ret);
5533 return ret;
5535 case WINED3DFMT_B5G5R5X1_UNORM:
5536 case WINED3DFMT_B5G5R5A1_UNORM:
5537 a = (a * 2) / 256;
5538 r = (r * 32) / 256;
5539 g = (g * 32) / 256;
5540 b = (b * 32) / 256;
5541 ret = a << 15;
5542 ret |= r << 10;
5543 ret |= g << 5;
5544 ret |= b << 0;
5545 TRACE("Returning %08x\n", ret);
5546 return ret;
5548 case WINED3DFMT_A8_UNORM:
5549 TRACE("Returning %08x\n", a);
5550 return a;
5552 case WINED3DFMT_B4G4R4X4_UNORM:
5553 case WINED3DFMT_B4G4R4A4_UNORM:
5554 a = (a * 16) / 256;
5555 r = (r * 16) / 256;
5556 g = (g * 16) / 256;
5557 b = (b * 16) / 256;
5558 ret = a << 12;
5559 ret |= r << 8;
5560 ret |= g << 4;
5561 ret |= b << 0;
5562 TRACE("Returning %08x\n", ret);
5563 return ret;
5565 case WINED3DFMT_B2G3R3_UNORM:
5566 r = (r * 8) / 256;
5567 g = (g * 8) / 256;
5568 b = (b * 4) / 256;
5569 ret = r << 5;
5570 ret |= g << 2;
5571 ret |= b << 0;
5572 TRACE("Returning %08x\n", ret);
5573 return ret;
5575 case WINED3DFMT_R8G8B8X8_UNORM:
5576 case WINED3DFMT_R8G8B8A8_UNORM:
5577 ret = a << 24;
5578 ret |= b << 16;
5579 ret |= g << 8;
5580 ret |= r << 0;
5581 TRACE("Returning %08x\n", ret);
5582 return ret;
5584 case WINED3DFMT_B10G10R10A2_UNORM:
5585 a = (a * 4) / 256;
5586 r = (r * 1024) / 256;
5587 g = (g * 1024) / 256;
5588 b = (b * 1024) / 256;
5589 ret = a << 30;
5590 ret |= r << 20;
5591 ret |= g << 10;
5592 ret |= b << 0;
5593 TRACE("Returning %08x\n", ret);
5594 return ret;
5596 case WINED3DFMT_R10G10B10A2_UNORM:
5597 a = (a * 4) / 256;
5598 r = (r * 1024) / 256;
5599 g = (g * 1024) / 256;
5600 b = (b * 1024) / 256;
5601 ret = a << 30;
5602 ret |= b << 20;
5603 ret |= g << 10;
5604 ret |= r << 0;
5605 TRACE("Returning %08x\n", ret);
5606 return ret;
5608 default:
5609 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5610 return 0;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5615 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5617 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5618 WINEDDBLTFX BltFx;
5620 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5622 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5623 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5624 return WINED3DERR_INVALIDCALL;
5627 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5628 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5629 color_fill_fbo(iface, pSurface, pRect, c);
5630 return WINED3D_OK;
5631 } else {
5632 /* Just forward this to the DirectDraw blitting engine */
5633 memset(&BltFx, 0, sizeof(BltFx));
5634 BltFx.dwSize = sizeof(BltFx);
5635 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5636 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5637 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5641 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5642 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5644 IWineD3DResource *resource;
5645 IWineD3DSurface *surface;
5646 HRESULT hr;
5648 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5649 if (FAILED(hr))
5651 ERR("Failed to get resource, hr %#x\n", hr);
5652 return;
5655 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5657 FIXME("Only supported on surface resources\n");
5658 IWineD3DResource_Release(resource);
5659 return;
5662 surface = (IWineD3DSurface *)resource;
5664 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5666 color_fill_fbo(iface, surface, NULL, color);
5668 else
5670 WINEDDBLTFX BltFx;
5671 WINED3DCOLOR c;
5673 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5675 c = ((DWORD)(color[2] * 255.0f));
5676 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5677 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5678 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5680 /* Just forward this to the DirectDraw blitting engine */
5681 memset(&BltFx, 0, sizeof(BltFx));
5682 BltFx.dwSize = sizeof(BltFx);
5683 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5684 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5685 if (FAILED(hr))
5687 ERR("Blt failed, hr %#x\n", hr);
5691 IWineD3DResource_Release(resource);
5694 /* rendertarget and depth stencil functions */
5695 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5700 ERR("(%p) : Only %d render targets are supported.\n",
5701 This, This->adapter->gl_info.limits.buffers);
5702 return WINED3DERR_INVALIDCALL;
5705 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5706 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5707 /* Note inc ref on returned surface */
5708 if(*ppRenderTarget != NULL)
5709 IWineD3DSurface_AddRef(*ppRenderTarget);
5710 return WINED3D_OK;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5714 IWineD3DSurface *front, IWineD3DSurface *back)
5716 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5717 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5718 IWineD3DSwapChainImpl *swapchain;
5719 HRESULT hr;
5721 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5723 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5725 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5726 return hr;
5729 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5731 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5732 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5733 return WINED3DERR_INVALIDCALL;
5736 if (back_impl)
5738 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5740 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5741 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5742 return WINED3DERR_INVALIDCALL;
5745 if (!swapchain->backBuffer)
5747 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5748 if (!swapchain->backBuffer)
5750 ERR("Failed to allocate back buffer array memory.\n");
5751 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5752 return E_OUTOFMEMORY;
5757 if (swapchain->frontBuffer != front)
5759 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5761 if (swapchain->frontBuffer)
5763 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5764 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5766 swapchain->frontBuffer = front;
5768 if (front)
5770 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5771 front_impl->Flags |= SFLAG_SWAPCHAIN;
5775 if (swapchain->backBuffer[0] != back)
5777 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5779 if (swapchain->backBuffer[0])
5781 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5782 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5784 swapchain->backBuffer[0] = back;
5786 if (back)
5788 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5789 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5790 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5791 swapchain->presentParms.BackBufferCount = 1;
5793 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5794 back_impl->Flags |= SFLAG_SWAPCHAIN;
5796 else
5798 swapchain->presentParms.BackBufferCount = 0;
5799 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5800 swapchain->backBuffer = NULL;
5804 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5805 return WINED3D_OK;
5808 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5810 *ppZStencilSurface = This->stencilBufferTarget;
5811 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5813 if(*ppZStencilSurface != NULL) {
5814 /* Note inc ref on returned surface */
5815 IWineD3DSurface_AddRef(*ppZStencilSurface);
5816 return WINED3D_OK;
5817 } else {
5818 return WINED3DERR_NOTFOUND;
5822 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5823 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5826 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5827 const struct wined3d_gl_info *gl_info;
5828 struct wined3d_context *context;
5829 GLenum gl_filter;
5830 POINT offset = {0, 0};
5832 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5833 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5834 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5835 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5837 switch (filter) {
5838 case WINED3DTEXF_LINEAR:
5839 gl_filter = GL_LINEAR;
5840 break;
5842 default:
5843 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5844 case WINED3DTEXF_NONE:
5845 case WINED3DTEXF_POINT:
5846 gl_filter = GL_NEAREST;
5847 break;
5850 /* Make sure the drawables are up-to-date. Note that loading the
5851 * destination surface isn't strictly required if we overwrite the
5852 * entire surface. */
5853 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5854 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5856 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5857 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5858 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5860 if (!context->valid)
5862 context_release(context);
5863 WARN("Invalid context, skipping blit.\n");
5864 return;
5867 gl_info = context->gl_info;
5869 if (!surface_is_offscreen(src_surface))
5871 GLenum buffer = surface_get_gl_buffer(src_surface);
5873 TRACE("Source surface %p is onscreen\n", src_surface);
5875 if(buffer == GL_FRONT) {
5876 RECT windowsize;
5877 UINT h;
5878 ClientToScreen(context->win_handle, &offset);
5879 GetClientRect(context->win_handle, &windowsize);
5880 h = windowsize.bottom - windowsize.top;
5881 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5882 src_rect->y1 = offset.y + h - src_rect->y1;
5883 src_rect->y2 = offset.y + h - src_rect->y2;
5884 } else {
5885 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5886 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5889 ENTER_GL();
5890 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5891 glReadBuffer(buffer);
5892 checkGLcall("glReadBuffer()");
5893 } else {
5894 TRACE("Source surface %p is offscreen\n", src_surface);
5895 ENTER_GL();
5896 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5897 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5898 glReadBuffer(GL_COLOR_ATTACHMENT0);
5899 checkGLcall("glReadBuffer()");
5900 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5902 LEAVE_GL();
5904 /* Attach dst surface to dst fbo */
5905 if (!surface_is_offscreen(dst_surface))
5907 GLenum buffer = surface_get_gl_buffer(dst_surface);
5909 TRACE("Destination surface %p is onscreen\n", dst_surface);
5911 if(buffer == GL_FRONT) {
5912 RECT windowsize;
5913 UINT h;
5914 ClientToScreen(context->win_handle, &offset);
5915 GetClientRect(context->win_handle, &windowsize);
5916 h = windowsize.bottom - windowsize.top;
5917 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5918 dst_rect->y1 = offset.y + h - dst_rect->y1;
5919 dst_rect->y2 = offset.y + h - dst_rect->y2;
5920 } else {
5921 /* Screen coords = window coords, surface height = window height */
5922 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5923 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5926 ENTER_GL();
5927 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5928 context_set_draw_buffer(context, buffer);
5930 else
5932 TRACE("Destination surface %p is offscreen\n", dst_surface);
5934 ENTER_GL();
5935 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5936 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5937 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5938 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5940 glDisable(GL_SCISSOR_TEST);
5941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5943 if (flip) {
5944 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5945 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5946 checkGLcall("glBlitFramebuffer()");
5947 } else {
5948 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5949 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5950 checkGLcall("glBlitFramebuffer()");
5953 LEAVE_GL();
5955 wglFlush(); /* Flush to ensure ordering across contexts. */
5957 context_release(context);
5959 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5962 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5963 BOOL set_viewport) {
5964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5966 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5968 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5970 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5971 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5972 return WINED3DERR_INVALIDCALL;
5975 /* MSDN says that null disables the render target
5976 but a device must always be associated with a render target
5977 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5979 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5980 FIXME("Trying to set render target 0 to NULL\n");
5981 return WINED3DERR_INVALIDCALL;
5983 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5984 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);
5985 return WINED3DERR_INVALIDCALL;
5988 /* If we are trying to set what we already have, don't bother */
5989 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5990 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5991 return WINED3D_OK;
5993 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5994 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5995 This->render_targets[RenderTargetIndex] = pRenderTarget;
5997 /* Render target 0 is special */
5998 if(RenderTargetIndex == 0 && set_viewport) {
5999 /* Finally, reset the viewport and scissor rect as the MSDN states.
6000 * Tests show that stateblock recording is ignored, the change goes
6001 * directly into the primary stateblock.
6003 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6004 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6005 This->stateBlock->viewport.X = 0;
6006 This->stateBlock->viewport.Y = 0;
6007 This->stateBlock->viewport.MaxZ = 1.0f;
6008 This->stateBlock->viewport.MinZ = 0.0f;
6009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6011 This->stateBlock->scissorRect.top = 0;
6012 This->stateBlock->scissorRect.left = 0;
6013 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6014 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6015 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6017 return WINED3D_OK;
6020 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6022 HRESULT hr = WINED3D_OK;
6023 IWineD3DSurface *tmp;
6025 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6027 if (pNewZStencil == This->stencilBufferTarget) {
6028 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6029 } else {
6030 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6031 * depending on the renter target implementation being used.
6032 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6033 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6034 * stencil buffer and incur an extra memory overhead
6035 ******************************************************/
6037 if (This->stencilBufferTarget) {
6038 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6039 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6040 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6041 } else {
6042 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6043 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6044 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6045 context_release(context);
6049 tmp = This->stencilBufferTarget;
6050 This->stencilBufferTarget = pNewZStencil;
6051 /* should we be calling the parent or the wined3d surface? */
6052 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6053 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6054 hr = WINED3D_OK;
6056 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6057 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6064 return hr;
6067 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6068 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6070 /* TODO: the use of Impl is deprecated. */
6071 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6072 WINED3DLOCKED_RECT lockedRect;
6074 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6076 /* some basic validation checks */
6077 if(This->cursorTexture) {
6078 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6079 ENTER_GL();
6080 glDeleteTextures(1, &This->cursorTexture);
6081 LEAVE_GL();
6082 context_release(context);
6083 This->cursorTexture = 0;
6086 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6087 This->haveHardwareCursor = TRUE;
6088 else
6089 This->haveHardwareCursor = FALSE;
6091 if(pCursorBitmap) {
6092 WINED3DLOCKED_RECT rect;
6094 /* MSDN: Cursor must be A8R8G8B8 */
6095 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6097 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6098 return WINED3DERR_INVALIDCALL;
6101 /* MSDN: Cursor must be smaller than the display mode */
6102 if(pSur->currentDesc.Width > This->ddraw_width ||
6103 pSur->currentDesc.Height > This->ddraw_height) {
6104 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);
6105 return WINED3DERR_INVALIDCALL;
6108 if (!This->haveHardwareCursor) {
6109 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6111 /* Do not store the surface's pointer because the application may
6112 * release it after setting the cursor image. Windows doesn't
6113 * addref the set surface, so we can't do this either without
6114 * creating circular refcount dependencies. Copy out the gl texture
6115 * instead.
6117 This->cursorWidth = pSur->currentDesc.Width;
6118 This->cursorHeight = pSur->currentDesc.Height;
6119 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6121 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6122 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6123 struct wined3d_context *context;
6124 char *mem, *bits = rect.pBits;
6125 GLint intfmt = format_desc->glInternal;
6126 GLint format = format_desc->glFormat;
6127 GLint type = format_desc->glType;
6128 INT height = This->cursorHeight;
6129 INT width = This->cursorWidth;
6130 INT bpp = format_desc->byte_count;
6131 DWORD sampler;
6132 INT i;
6134 /* Reformat the texture memory (pitch and width can be
6135 * different) */
6136 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6137 for(i = 0; i < height; i++)
6138 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6139 IWineD3DSurface_UnlockRect(pCursorBitmap);
6141 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6143 ENTER_GL();
6145 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6147 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6148 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6151 /* Make sure that a proper texture unit is selected */
6152 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6153 checkGLcall("glActiveTextureARB");
6154 sampler = This->rev_tex_unit_map[0];
6155 if (sampler != WINED3D_UNMAPPED_STAGE)
6157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6159 /* Create a new cursor texture */
6160 glGenTextures(1, &This->cursorTexture);
6161 checkGLcall("glGenTextures");
6162 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6163 checkGLcall("glBindTexture");
6164 /* Copy the bitmap memory into the cursor texture */
6165 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6166 HeapFree(GetProcessHeap(), 0, mem);
6167 checkGLcall("glTexImage2D");
6169 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6171 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6172 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6175 LEAVE_GL();
6177 context_release(context);
6179 else
6181 FIXME("A cursor texture was not returned.\n");
6182 This->cursorTexture = 0;
6185 else
6187 /* Draw a hardware cursor */
6188 ICONINFO cursorInfo;
6189 HCURSOR cursor;
6190 /* Create and clear maskBits because it is not needed for
6191 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6192 * chunks. */
6193 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6194 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6195 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6196 WINED3DLOCK_NO_DIRTY_UPDATE |
6197 WINED3DLOCK_READONLY
6199 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6200 pSur->currentDesc.Height);
6202 cursorInfo.fIcon = FALSE;
6203 cursorInfo.xHotspot = XHotSpot;
6204 cursorInfo.yHotspot = YHotSpot;
6205 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6206 1, 1, maskBits);
6207 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6208 1, 32, lockedRect.pBits);
6209 IWineD3DSurface_UnlockRect(pCursorBitmap);
6210 /* Create our cursor and clean up. */
6211 cursor = CreateIconIndirect(&cursorInfo);
6212 SetCursor(cursor);
6213 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6214 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6215 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6216 This->hardwareCursor = cursor;
6217 HeapFree(GetProcessHeap(), 0, maskBits);
6221 This->xHotSpot = XHotSpot;
6222 This->yHotSpot = YHotSpot;
6223 return WINED3D_OK;
6226 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6228 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6230 This->xScreenSpace = XScreenSpace;
6231 This->yScreenSpace = YScreenSpace;
6233 return;
6237 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6239 BOOL oldVisible = This->bCursorVisible;
6240 POINT pt;
6242 TRACE("(%p) : visible(%d)\n", This, bShow);
6245 * When ShowCursor is first called it should make the cursor appear at the OS's last
6246 * known cursor position. Because of this, some applications just repetitively call
6247 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6249 GetCursorPos(&pt);
6250 This->xScreenSpace = pt.x;
6251 This->yScreenSpace = pt.y;
6253 if (This->haveHardwareCursor) {
6254 This->bCursorVisible = bShow;
6255 if (bShow)
6256 SetCursor(This->hardwareCursor);
6257 else
6258 SetCursor(NULL);
6260 else
6262 if (This->cursorTexture)
6263 This->bCursorVisible = bShow;
6266 return oldVisible;
6269 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6270 TRACE("checking resource %p for eviction\n", resource);
6271 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6272 TRACE("Evicting %p\n", resource);
6273 IWineD3DResource_UnLoad(resource);
6275 IWineD3DResource_Release(resource);
6276 return S_OK;
6279 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6281 TRACE("iface %p.\n", iface);
6283 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6284 return WINED3D_OK;
6287 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6289 IWineD3DDeviceImpl *device = surface->resource.device;
6290 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6292 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6293 if(surface->Flags & SFLAG_DIBSECTION) {
6294 /* Release the DC */
6295 SelectObject(surface->hDC, surface->dib.holdbitmap);
6296 DeleteDC(surface->hDC);
6297 /* Release the DIB section */
6298 DeleteObject(surface->dib.DIBsection);
6299 surface->dib.bitmap_data = NULL;
6300 surface->resource.allocatedMemory = NULL;
6301 surface->Flags &= ~SFLAG_DIBSECTION;
6303 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6304 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6305 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6306 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6308 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6309 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6310 } else {
6311 surface->pow2Width = surface->pow2Height = 1;
6312 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6313 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6315 surface->glRect.left = 0;
6316 surface->glRect.top = 0;
6317 surface->glRect.right = surface->pow2Width;
6318 surface->glRect.bottom = surface->pow2Height;
6320 if (surface->texture_name)
6322 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6323 ENTER_GL();
6324 glDeleteTextures(1, &surface->texture_name);
6325 LEAVE_GL();
6326 context_release(context);
6327 surface->texture_name = 0;
6328 surface->Flags &= ~SFLAG_CLIENT;
6330 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6331 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6332 surface->Flags |= SFLAG_NONPOW2;
6333 } else {
6334 surface->Flags &= ~SFLAG_NONPOW2;
6336 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6337 surface->resource.allocatedMemory = NULL;
6338 surface->resource.heapMemory = NULL;
6339 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6341 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6342 * to a FBO */
6343 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6345 return E_OUTOFMEMORY;
6347 return WINED3D_OK;
6350 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6351 TRACE("Unloading resource %p\n", resource);
6352 IWineD3DResource_UnLoad(resource);
6353 IWineD3DResource_Release(resource);
6354 return S_OK;
6357 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6359 UINT i, count;
6360 WINED3DDISPLAYMODE m;
6361 HRESULT hr;
6363 /* All Windowed modes are supported, as is leaving the current mode */
6364 if(pp->Windowed) return TRUE;
6365 if(!pp->BackBufferWidth) return TRUE;
6366 if(!pp->BackBufferHeight) return TRUE;
6368 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6369 for(i = 0; i < count; i++) {
6370 memset(&m, 0, sizeof(m));
6371 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6372 if(FAILED(hr)) {
6373 ERR("EnumAdapterModes failed\n");
6375 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6376 /* Mode found, it is supported */
6377 return TRUE;
6380 /* Mode not found -> not supported */
6381 return FALSE;
6384 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6386 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6387 const struct wined3d_gl_info *gl_info;
6388 struct wined3d_context *context;
6389 IWineD3DBaseShaderImpl *shader;
6391 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6392 gl_info = context->gl_info;
6394 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6395 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6396 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6399 ENTER_GL();
6400 if(This->depth_blt_texture) {
6401 glDeleteTextures(1, &This->depth_blt_texture);
6402 This->depth_blt_texture = 0;
6404 if (This->depth_blt_rb) {
6405 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6406 This->depth_blt_rb = 0;
6407 This->depth_blt_rb_w = 0;
6408 This->depth_blt_rb_h = 0;
6410 LEAVE_GL();
6412 This->blitter->free_private(iface);
6413 This->frag_pipe->free_private(iface);
6414 This->shader_backend->shader_free_private(iface);
6415 destroy_dummy_textures(This, gl_info);
6417 context_release(context);
6419 while (This->numContexts)
6421 context_destroy(This, This->contexts[0]);
6423 HeapFree(GetProcessHeap(), 0, swapchain->context);
6424 swapchain->context = NULL;
6425 swapchain->num_contexts = 0;
6428 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6430 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6431 struct wined3d_context *context;
6432 HRESULT hr;
6433 IWineD3DSurfaceImpl *target;
6435 /* Recreate the primary swapchain's context */
6436 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6437 if (!swapchain->context)
6439 ERR("Failed to allocate memory for swapchain context array.\n");
6440 return E_OUTOFMEMORY;
6443 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6444 if (!(context = context_create(swapchain, target)))
6446 WARN("Failed to create context.\n");
6447 HeapFree(GetProcessHeap(), 0, swapchain->context);
6448 return E_FAIL;
6451 swapchain->context[0] = context;
6452 swapchain->num_contexts = 1;
6453 create_dummy_textures(This);
6454 context_release(context);
6456 hr = This->shader_backend->shader_alloc_private(iface);
6457 if (FAILED(hr))
6459 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6460 goto err;
6463 hr = This->frag_pipe->alloc_private(iface);
6464 if (FAILED(hr))
6466 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6467 This->shader_backend->shader_free_private(iface);
6468 goto err;
6471 hr = This->blitter->alloc_private(iface);
6472 if (FAILED(hr))
6474 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6475 This->frag_pipe->free_private(iface);
6476 This->shader_backend->shader_free_private(iface);
6477 goto err;
6480 return WINED3D_OK;
6482 err:
6483 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6484 destroy_dummy_textures(This, context->gl_info);
6485 context_release(context);
6486 context_destroy(This, context);
6487 HeapFree(GetProcessHeap(), 0, swapchain->context);
6488 swapchain->num_contexts = 0;
6489 return hr;
6492 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6494 IWineD3DSwapChainImpl *swapchain;
6495 HRESULT hr;
6496 BOOL DisplayModeChanged = FALSE;
6497 WINED3DDISPLAYMODE mode;
6498 TRACE("(%p)\n", This);
6500 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6501 if(FAILED(hr)) {
6502 ERR("Failed to get the first implicit swapchain\n");
6503 return hr;
6506 if(!is_display_mode_supported(This, pPresentationParameters)) {
6507 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6508 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6509 pPresentationParameters->BackBufferHeight);
6510 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6511 return WINED3DERR_INVALIDCALL;
6514 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6515 * on an existing gl context, so there's no real need for recreation.
6517 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6519 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6521 TRACE("New params:\n");
6522 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6523 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6524 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6525 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6526 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6527 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6528 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6529 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6530 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6531 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6532 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6533 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6534 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6536 /* No special treatment of these parameters. Just store them */
6537 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6538 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6539 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6540 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6542 /* What to do about these? */
6543 if(pPresentationParameters->BackBufferCount != 0 &&
6544 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6545 ERR("Cannot change the back buffer count yet\n");
6547 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6548 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6549 ERR("Cannot change the back buffer format yet\n");
6551 if(pPresentationParameters->hDeviceWindow != NULL &&
6552 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6553 ERR("Cannot change the device window yet\n");
6555 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6556 HRESULT hrc;
6558 TRACE("Creating the depth stencil buffer\n");
6560 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6561 This->parent,
6562 pPresentationParameters->BackBufferWidth,
6563 pPresentationParameters->BackBufferHeight,
6564 pPresentationParameters->AutoDepthStencilFormat,
6565 pPresentationParameters->MultiSampleType,
6566 pPresentationParameters->MultiSampleQuality,
6567 FALSE,
6568 &This->auto_depth_stencil_buffer);
6570 if (FAILED(hrc)) {
6571 ERR("Failed to create the depth stencil buffer\n");
6572 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6573 return WINED3DERR_INVALIDCALL;
6577 /* Reset the depth stencil */
6578 if (pPresentationParameters->EnableAutoDepthStencil)
6579 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6580 else
6581 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6583 TRACE("Resetting stateblock\n");
6584 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6585 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6587 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6589 if(pPresentationParameters->Windowed) {
6590 mode.Width = swapchain->orig_width;
6591 mode.Height = swapchain->orig_height;
6592 mode.RefreshRate = 0;
6593 mode.Format = swapchain->presentParms.BackBufferFormat;
6594 } else {
6595 mode.Width = pPresentationParameters->BackBufferWidth;
6596 mode.Height = pPresentationParameters->BackBufferHeight;
6597 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6598 mode.Format = swapchain->presentParms.BackBufferFormat;
6601 /* Should Width == 800 && Height == 0 set 800x600? */
6602 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6603 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6604 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6606 UINT i;
6608 if(!pPresentationParameters->Windowed) {
6609 DisplayModeChanged = TRUE;
6611 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6612 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6614 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6615 if(FAILED(hr))
6617 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6618 return hr;
6621 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6622 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6623 if(FAILED(hr))
6625 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6626 return hr;
6629 if(This->auto_depth_stencil_buffer) {
6630 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6631 if(FAILED(hr))
6633 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6634 return hr;
6639 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6640 || DisplayModeChanged)
6642 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6644 if (!pPresentationParameters->Windowed)
6646 if(swapchain->presentParms.Windowed) {
6647 /* switch from windowed to fs */
6648 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6649 pPresentationParameters->BackBufferHeight);
6650 } else {
6651 /* Fullscreen -> fullscreen mode change */
6652 MoveWindow(swapchain->device_window, 0, 0,
6653 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6654 TRUE);
6657 else if (!swapchain->presentParms.Windowed)
6659 /* Fullscreen -> windowed switch */
6660 swapchain_restore_fullscreen_window(swapchain);
6662 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6663 } else if(!pPresentationParameters->Windowed) {
6664 DWORD style = This->style, exStyle = This->exStyle;
6665 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6666 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6667 * Reset to clear up their mess. Guild Wars also loses the device during that.
6669 This->style = 0;
6670 This->exStyle = 0;
6671 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6672 pPresentationParameters->BackBufferHeight);
6673 This->style = style;
6674 This->exStyle = exStyle;
6677 /* Note: No parent needed for initial internal stateblock */
6678 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6679 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6680 else TRACE("Created stateblock %p\n", This->stateBlock);
6681 This->updateStateBlock = This->stateBlock;
6682 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6684 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6685 if(FAILED(hr)) {
6686 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6689 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6691 RECT client_rect;
6692 GetClientRect(swapchain->win_handle, &client_rect);
6694 if(!swapchain->presentParms.BackBufferCount)
6696 TRACE("Single buffered rendering\n");
6697 swapchain->render_to_fbo = FALSE;
6699 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6700 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6702 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6703 swapchain->presentParms.BackBufferWidth,
6704 swapchain->presentParms.BackBufferHeight,
6705 client_rect.right, client_rect.bottom);
6706 swapchain->render_to_fbo = TRUE;
6708 else
6710 TRACE("Rendering directly to GL_BACK\n");
6711 swapchain->render_to_fbo = FALSE;
6715 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6716 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6718 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6719 * first use
6721 return hr;
6724 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6726 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6728 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6730 return WINED3D_OK;
6734 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6736 TRACE("(%p) : pParameters %p\n", This, pParameters);
6738 *pParameters = This->createParms;
6739 return WINED3D_OK;
6742 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6743 IWineD3DSwapChain *swapchain;
6745 TRACE("Relaying to swapchain\n");
6747 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6748 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6749 IWineD3DSwapChain_Release(swapchain);
6753 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6754 IWineD3DSwapChain *swapchain;
6756 TRACE("Relaying to swapchain\n");
6758 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6759 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6760 IWineD3DSwapChain_Release(swapchain);
6765 /** ********************************************************
6766 * Notification functions
6767 ** ********************************************************/
6768 /** This function must be called in the release of a resource when ref == 0,
6769 * the contents of resource must still be correct,
6770 * any handles to other resource held by the caller must be closed
6771 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6772 *****************************************************/
6773 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6775 TRACE("(%p) : Adding resource %p\n", This, resource);
6777 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6780 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6782 TRACE("(%p) : Removing resource %p\n", This, resource);
6784 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6787 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6789 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6790 int counter;
6792 TRACE("(%p) : resource %p\n", This, resource);
6794 context_resource_released((IWineD3DDevice *)This, resource, type);
6796 switch (type) {
6797 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6798 case WINED3DRTYPE_SURFACE: {
6799 unsigned int i;
6801 if (This->d3d_initialized)
6803 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6805 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6806 This->render_targets[i] = NULL;
6809 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6810 This->stencilBufferTarget = NULL;
6814 break;
6816 case WINED3DRTYPE_TEXTURE:
6817 case WINED3DRTYPE_CUBETEXTURE:
6818 case WINED3DRTYPE_VOLUMETEXTURE:
6819 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6820 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6821 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6822 This->stateBlock->textures[counter] = NULL;
6824 if (This->updateStateBlock != This->stateBlock ){
6825 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6826 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6827 This->updateStateBlock->textures[counter] = NULL;
6831 break;
6832 case WINED3DRTYPE_VOLUME:
6833 /* TODO: nothing really? */
6834 break;
6835 case WINED3DRTYPE_BUFFER:
6837 int streamNumber;
6838 TRACE("Cleaning up stream pointers\n");
6840 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6841 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6842 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6844 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6845 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6846 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6847 This->updateStateBlock->streamSource[streamNumber] = 0;
6848 /* Set changed flag? */
6851 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) */
6852 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6853 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6854 This->stateBlock->streamSource[streamNumber] = 0;
6859 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6860 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6861 This->updateStateBlock->pIndexData = NULL;
6864 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6865 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6866 This->stateBlock->pIndexData = NULL;
6870 break;
6872 default:
6873 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6874 break;
6878 /* Remove the resource from the resourceStore */
6879 device_resource_remove(This, resource);
6881 TRACE("Resource released\n");
6885 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6887 IWineD3DResourceImpl *resource, *cursor;
6888 HRESULT ret;
6889 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6891 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6892 TRACE("enumerating resource %p\n", resource);
6893 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6894 ret = pCallback((IWineD3DResource *) resource, pData);
6895 if(ret == S_FALSE) {
6896 TRACE("Canceling enumeration\n");
6897 break;
6900 return WINED3D_OK;
6903 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6906 IWineD3DResourceImpl *resource;
6908 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6910 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6911 if (type == WINED3DRTYPE_SURFACE)
6913 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6915 TRACE("Found surface %p for dc %p.\n", resource, dc);
6916 *surface = (IWineD3DSurface *)resource;
6917 return WINED3D_OK;
6922 return WINED3DERR_INVALIDCALL;
6925 /**********************************************************
6926 * IWineD3DDevice VTbl follows
6927 **********************************************************/
6929 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6931 /*** IUnknown methods ***/
6932 IWineD3DDeviceImpl_QueryInterface,
6933 IWineD3DDeviceImpl_AddRef,
6934 IWineD3DDeviceImpl_Release,
6935 /*** IWineD3DDevice methods ***/
6936 IWineD3DDeviceImpl_GetParent,
6937 /*** Creation methods**/
6938 IWineD3DDeviceImpl_CreateBuffer,
6939 IWineD3DDeviceImpl_CreateVertexBuffer,
6940 IWineD3DDeviceImpl_CreateIndexBuffer,
6941 IWineD3DDeviceImpl_CreateStateBlock,
6942 IWineD3DDeviceImpl_CreateSurface,
6943 IWineD3DDeviceImpl_CreateRendertargetView,
6944 IWineD3DDeviceImpl_CreateTexture,
6945 IWineD3DDeviceImpl_CreateVolumeTexture,
6946 IWineD3DDeviceImpl_CreateVolume,
6947 IWineD3DDeviceImpl_CreateCubeTexture,
6948 IWineD3DDeviceImpl_CreateQuery,
6949 IWineD3DDeviceImpl_CreateSwapChain,
6950 IWineD3DDeviceImpl_CreateVertexDeclaration,
6951 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6952 IWineD3DDeviceImpl_CreateVertexShader,
6953 IWineD3DDeviceImpl_CreateGeometryShader,
6954 IWineD3DDeviceImpl_CreatePixelShader,
6955 IWineD3DDeviceImpl_CreatePalette,
6956 /*** Odd functions **/
6957 IWineD3DDeviceImpl_Init3D,
6958 IWineD3DDeviceImpl_InitGDI,
6959 IWineD3DDeviceImpl_Uninit3D,
6960 IWineD3DDeviceImpl_UninitGDI,
6961 IWineD3DDeviceImpl_SetMultithreaded,
6962 IWineD3DDeviceImpl_EvictManagedResources,
6963 IWineD3DDeviceImpl_GetAvailableTextureMem,
6964 IWineD3DDeviceImpl_GetBackBuffer,
6965 IWineD3DDeviceImpl_GetCreationParameters,
6966 IWineD3DDeviceImpl_GetDeviceCaps,
6967 IWineD3DDeviceImpl_GetDirect3D,
6968 IWineD3DDeviceImpl_GetDisplayMode,
6969 IWineD3DDeviceImpl_SetDisplayMode,
6970 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6971 IWineD3DDeviceImpl_GetRasterStatus,
6972 IWineD3DDeviceImpl_GetSwapChain,
6973 IWineD3DDeviceImpl_Reset,
6974 IWineD3DDeviceImpl_SetDialogBoxMode,
6975 IWineD3DDeviceImpl_SetCursorProperties,
6976 IWineD3DDeviceImpl_SetCursorPosition,
6977 IWineD3DDeviceImpl_ShowCursor,
6978 /*** Getters and setters **/
6979 IWineD3DDeviceImpl_SetClipPlane,
6980 IWineD3DDeviceImpl_GetClipPlane,
6981 IWineD3DDeviceImpl_SetClipStatus,
6982 IWineD3DDeviceImpl_GetClipStatus,
6983 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6984 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6985 IWineD3DDeviceImpl_SetDepthStencilSurface,
6986 IWineD3DDeviceImpl_GetDepthStencilSurface,
6987 IWineD3DDeviceImpl_SetGammaRamp,
6988 IWineD3DDeviceImpl_GetGammaRamp,
6989 IWineD3DDeviceImpl_SetIndexBuffer,
6990 IWineD3DDeviceImpl_GetIndexBuffer,
6991 IWineD3DDeviceImpl_SetBaseVertexIndex,
6992 IWineD3DDeviceImpl_GetBaseVertexIndex,
6993 IWineD3DDeviceImpl_SetLight,
6994 IWineD3DDeviceImpl_GetLight,
6995 IWineD3DDeviceImpl_SetLightEnable,
6996 IWineD3DDeviceImpl_GetLightEnable,
6997 IWineD3DDeviceImpl_SetMaterial,
6998 IWineD3DDeviceImpl_GetMaterial,
6999 IWineD3DDeviceImpl_SetNPatchMode,
7000 IWineD3DDeviceImpl_GetNPatchMode,
7001 IWineD3DDeviceImpl_SetPaletteEntries,
7002 IWineD3DDeviceImpl_GetPaletteEntries,
7003 IWineD3DDeviceImpl_SetPixelShader,
7004 IWineD3DDeviceImpl_GetPixelShader,
7005 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7006 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7007 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7008 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7009 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7010 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7011 IWineD3DDeviceImpl_SetRenderState,
7012 IWineD3DDeviceImpl_GetRenderState,
7013 IWineD3DDeviceImpl_SetRenderTarget,
7014 IWineD3DDeviceImpl_GetRenderTarget,
7015 IWineD3DDeviceImpl_SetFrontBackBuffers,
7016 IWineD3DDeviceImpl_SetSamplerState,
7017 IWineD3DDeviceImpl_GetSamplerState,
7018 IWineD3DDeviceImpl_SetScissorRect,
7019 IWineD3DDeviceImpl_GetScissorRect,
7020 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7021 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7022 IWineD3DDeviceImpl_SetStreamSource,
7023 IWineD3DDeviceImpl_GetStreamSource,
7024 IWineD3DDeviceImpl_SetStreamSourceFreq,
7025 IWineD3DDeviceImpl_GetStreamSourceFreq,
7026 IWineD3DDeviceImpl_SetTexture,
7027 IWineD3DDeviceImpl_GetTexture,
7028 IWineD3DDeviceImpl_SetTextureStageState,
7029 IWineD3DDeviceImpl_GetTextureStageState,
7030 IWineD3DDeviceImpl_SetTransform,
7031 IWineD3DDeviceImpl_GetTransform,
7032 IWineD3DDeviceImpl_SetVertexDeclaration,
7033 IWineD3DDeviceImpl_GetVertexDeclaration,
7034 IWineD3DDeviceImpl_SetVertexShader,
7035 IWineD3DDeviceImpl_GetVertexShader,
7036 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7037 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7038 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7039 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7040 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7041 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7042 IWineD3DDeviceImpl_SetViewport,
7043 IWineD3DDeviceImpl_GetViewport,
7044 IWineD3DDeviceImpl_MultiplyTransform,
7045 IWineD3DDeviceImpl_ValidateDevice,
7046 IWineD3DDeviceImpl_ProcessVertices,
7047 /*** State block ***/
7048 IWineD3DDeviceImpl_BeginStateBlock,
7049 IWineD3DDeviceImpl_EndStateBlock,
7050 /*** Scene management ***/
7051 IWineD3DDeviceImpl_BeginScene,
7052 IWineD3DDeviceImpl_EndScene,
7053 IWineD3DDeviceImpl_Present,
7054 IWineD3DDeviceImpl_Clear,
7055 IWineD3DDeviceImpl_ClearRendertargetView,
7056 /*** Drawing ***/
7057 IWineD3DDeviceImpl_SetPrimitiveType,
7058 IWineD3DDeviceImpl_GetPrimitiveType,
7059 IWineD3DDeviceImpl_DrawPrimitive,
7060 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7061 IWineD3DDeviceImpl_DrawPrimitiveUP,
7062 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7063 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7064 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7065 IWineD3DDeviceImpl_DrawRectPatch,
7066 IWineD3DDeviceImpl_DrawTriPatch,
7067 IWineD3DDeviceImpl_DeletePatch,
7068 IWineD3DDeviceImpl_ColorFill,
7069 IWineD3DDeviceImpl_UpdateTexture,
7070 IWineD3DDeviceImpl_UpdateSurface,
7071 IWineD3DDeviceImpl_GetFrontBufferData,
7072 /*** object tracking ***/
7073 IWineD3DDeviceImpl_EnumResources,
7074 IWineD3DDeviceImpl_GetSurfaceFromDC,
7075 IWineD3DDeviceImpl_AcquireFocusWindow,
7076 IWineD3DDeviceImpl_ReleaseFocusWindow,
7079 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7080 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7081 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7083 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7084 const struct fragment_pipeline *fragment_pipeline;
7085 struct shader_caps shader_caps;
7086 struct fragment_caps ffp_caps;
7087 WINED3DDISPLAYMODE mode;
7088 unsigned int i;
7089 HRESULT hr;
7091 device->lpVtbl = &IWineD3DDevice_Vtbl;
7092 device->ref = 1;
7093 device->wined3d = (IWineD3D *)wined3d;
7094 IWineD3D_AddRef(device->wined3d);
7095 device->adapter = wined3d->adapter_count ? adapter : NULL;
7096 device->parent = parent;
7097 device->device_parent = device_parent;
7098 list_init(&device->resources);
7099 list_init(&device->shaders);
7101 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7102 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7104 /* Get the initial screen setup for ddraw. */
7105 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7106 if (FAILED(hr))
7108 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7109 IWineD3D_Release(device->wined3d);
7110 return hr;
7112 device->ddraw_width = mode.Width;
7113 device->ddraw_height = mode.Height;
7114 device->ddraw_format = mode.Format;
7116 /* Save the creation parameters. */
7117 device->createParms.AdapterOrdinal = adapter_idx;
7118 device->createParms.DeviceType = device_type;
7119 device->createParms.hFocusWindow = focus_window;
7120 device->createParms.BehaviorFlags = flags;
7122 device->devType = device_type;
7123 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7125 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7126 device->shader_backend = adapter->shader_backend;
7128 memset(&shader_caps, 0, sizeof(shader_caps));
7129 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7130 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7131 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7132 device->vs_clipping = shader_caps.VSClipping;
7134 memset(&ffp_caps, 0, sizeof(ffp_caps));
7135 fragment_pipeline = adapter->fragment_pipe;
7136 device->frag_pipe = fragment_pipeline;
7137 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7138 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7140 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7141 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7142 if (FAILED(hr))
7144 ERR("Failed to compile state table, hr %#x.\n", hr);
7145 IWineD3D_Release(device->wined3d);
7146 return hr;
7149 device->blitter = adapter->blitter;
7151 return WINED3D_OK;
7155 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7156 DWORD rep = This->StateTable[state].representative;
7157 struct wined3d_context *context;
7158 DWORD idx;
7159 BYTE shift;
7160 UINT i;
7162 for(i = 0; i < This->numContexts; i++) {
7163 context = This->contexts[i];
7164 if(isStateDirty(context, rep)) continue;
7166 context->dirtyArray[context->numDirtyEntries++] = rep;
7167 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7168 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7169 context->isStateDirty[idx] |= (1 << shift);
7173 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7175 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7176 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7177 *width = surface->pow2Width;
7178 *height = surface->pow2Height;
7181 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7183 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7184 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7185 * current context's drawable, which is the size of the back buffer of the swapchain
7186 * the active context belongs to. */
7187 *width = swapchain->presentParms.BackBufferWidth;
7188 *height = swapchain->presentParms.BackBufferHeight;
7191 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7192 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7194 if (device->filter_messages)
7196 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7197 window, message, wparam, lparam);
7198 return DefWindowProcW(window, message, wparam, lparam);
7201 if (message == WM_DESTROY)
7203 TRACE("unregister window %p.\n", window);
7204 wined3d_unregister_window(window);
7206 if (device->focus_window == window) device->focus_window = NULL;
7207 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7210 return CallWindowProcW(proc, window, message, wparam, lparam);