wined3d: Avoid some common invalid context accesses.
[wine/hacks.git] / dlls / wined3d / device.c
blobbd1345154594385804a899e7faf8d127969ac36b
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 if (!This->stateBlock->streamIsUP)
310 WORD map = stream_info->use_map;
312 /* PreLoad all the vertex buffers. */
313 for (i = 0; map; map >>= 1, ++i)
315 struct wined3d_stream_info_element *element;
316 struct wined3d_buffer *buffer;
318 if (!(map & 1)) continue;
320 element = &stream_info->elements[i];
321 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
322 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
324 /* If PreLoad dropped the buffer object, update the stream info. */
325 if (buffer->buffer_object != element->buffer_object)
327 element->buffer_object = 0;
328 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
334 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
335 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
337 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
338 e->format_desc = format_desc;
339 e->stride = strided->dwStride;
340 e->data = strided->lpData;
341 e->stream_idx = 0;
342 e->buffer_object = 0;
345 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
346 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
348 unsigned int i;
350 memset(stream_info, 0, sizeof(*stream_info));
352 if (strided->position.lpData)
353 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
354 if (strided->normal.lpData)
355 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
356 if (strided->diffuse.lpData)
357 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
358 if (strided->specular.lpData)
359 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
361 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
363 if (strided->texCoords[i].lpData)
364 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
365 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
368 stream_info->position_transformed = strided->position_transformed;
370 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
372 if (!stream_info->elements[i].format_desc) continue;
374 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
375 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
377 stream_info->swizzle_map |= 1 << i;
379 stream_info->use_map |= 1 << i;
383 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
385 TRACE("Strided Data:\n");
386 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
387 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
388 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
389 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
403 /* Context activation is done by the caller. */
404 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
406 struct wined3d_stream_info *stream_info = &device->strided_streams;
407 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
408 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
409 BOOL fixup = FALSE;
411 if (device->up_strided)
413 /* Note: this is a ddraw fixed-function code path. */
414 TRACE("=============================== Strided Input ================================\n");
415 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
416 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
418 else
420 TRACE("============================= Vertex Declaration =============================\n");
421 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
424 if (vs && !stream_info->position_transformed)
426 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
428 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
429 device->useDrawStridedSlow = TRUE;
431 else
433 device->useDrawStridedSlow = FALSE;
436 else
438 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
439 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
440 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
442 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
444 device->useDrawStridedSlow = TRUE;
446 else
448 device->useDrawStridedSlow = FALSE;
453 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
455 IWineD3DBaseTextureImpl *texture;
456 enum WINED3DSRGB srgb;
458 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
459 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
460 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
463 void device_preload_textures(IWineD3DDeviceImpl *device)
465 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
466 unsigned int i;
468 if (use_vs(stateblock))
470 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
472 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
473 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
477 if (use_ps(stateblock))
479 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, i);
485 else
487 WORD ffu_map = device->fixed_function_usage_map;
489 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
491 if (ffu_map & 1)
492 device_preload_texture(stateblock, i);
497 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
499 struct wined3d_context **new_array;
501 TRACE("Adding context %p.\n", context);
503 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
504 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
506 if (!new_array)
508 ERR("Failed to grow the context array.\n");
509 return FALSE;
512 new_array[device->numContexts++] = context;
513 device->contexts = new_array;
514 return TRUE;
517 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
519 struct wined3d_context **new_array;
520 BOOL found = FALSE;
521 UINT i;
523 TRACE("Removing context %p.\n", context);
525 for (i = 0; i < device->numContexts; ++i)
527 if (device->contexts[i] == context)
529 found = TRUE;
530 break;
534 if (!found)
536 ERR("Context %p doesn't exist in context array.\n", context);
537 return;
540 if (!--device->numContexts)
542 HeapFree(GetProcessHeap(), 0, device->contexts);
543 device->contexts = NULL;
544 return;
547 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
548 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
549 if (!new_array)
551 ERR("Failed to shrink context array. Oh well.\n");
552 return;
555 device->contexts = new_array;
559 /**********************************************************
560 * IUnknown parts follows
561 **********************************************************/
563 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
567 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
568 if (IsEqualGUID(riid, &IID_IUnknown)
569 || IsEqualGUID(riid, &IID_IWineD3DBase)
570 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
571 IUnknown_AddRef(iface);
572 *ppobj = This;
573 return S_OK;
575 *ppobj = NULL;
576 return E_NOINTERFACE;
579 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
581 ULONG refCount = InterlockedIncrement(&This->ref);
583 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
584 return refCount;
587 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 ULONG refCount = InterlockedDecrement(&This->ref);
591 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
593 if (!refCount) {
594 UINT i;
596 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
597 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
598 This->multistate_funcs[i] = NULL;
601 /* TODO: Clean up all the surfaces and textures! */
602 /* NOTE: You must release the parent if the object was created via a callback
603 ** ***************************/
605 if (!list_empty(&This->resources)) {
606 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
607 dumpResources(&This->resources);
610 if(This->contexts) ERR("Context array not freed!\n");
611 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
612 This->haveHardwareCursor = FALSE;
614 IWineD3D_Release(This->wined3d);
615 This->wined3d = NULL;
616 HeapFree(GetProcessHeap(), 0, This);
617 TRACE("Freed device %p\n", This);
618 This = NULL;
620 return refCount;
623 /**********************************************************
624 * IWineD3DDevice implementation follows
625 **********************************************************/
626 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
628 *pParent = This->parent;
629 IUnknown_AddRef(This->parent);
630 return WINED3D_OK;
633 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
634 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 struct wined3d_buffer *object;
638 HRESULT hr;
640 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
642 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
643 if (!object)
645 ERR("Failed to allocate memory\n");
646 return E_OUTOFMEMORY;
649 FIXME("Ignoring access flags (pool)\n");
651 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
652 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
653 if (FAILED(hr))
655 WARN("Failed to initialize buffer, hr %#x.\n", hr);
656 HeapFree(GetProcessHeap(), 0, object);
657 return hr;
659 object->desc = *desc;
661 TRACE("Created buffer %p.\n", object);
663 *buffer = (IWineD3DBuffer *)object;
665 return WINED3D_OK;
668 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
669 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
670 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
673 struct wined3d_buffer *object;
674 HRESULT hr;
676 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
677 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
679 if (Pool == WINED3DPOOL_SCRATCH)
681 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
682 * anyway, SCRATCH vertex buffers aren't usable anywhere
684 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
685 *ppVertexBuffer = NULL;
686 return WINED3DERR_INVALIDCALL;
689 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
690 if (!object)
692 ERR("Out of memory\n");
693 *ppVertexBuffer = NULL;
694 return WINED3DERR_OUTOFVIDEOMEMORY;
697 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
698 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
699 if (FAILED(hr))
701 WARN("Failed to initialize buffer, hr %#x.\n", hr);
702 HeapFree(GetProcessHeap(), 0, object);
703 return hr;
706 TRACE("Created buffer %p.\n", object);
707 *ppVertexBuffer = (IWineD3DBuffer *)object;
709 return WINED3D_OK;
712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
713 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
714 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
717 struct wined3d_buffer *object;
718 HRESULT hr;
720 TRACE("(%p) Creating index buffer\n", This);
722 /* Allocate the storage for the device */
723 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
724 if (!object)
726 ERR("Out of memory\n");
727 *ppIndexBuffer = NULL;
728 return WINED3DERR_OUTOFVIDEOMEMORY;
731 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
732 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
733 parent, parent_ops);
734 if (FAILED(hr))
736 WARN("Failed to initialize buffer, hr %#x\n", hr);
737 HeapFree(GetProcessHeap(), 0, object);
738 return hr;
741 TRACE("Created buffer %p.\n", object);
743 *ppIndexBuffer = (IWineD3DBuffer *) object;
745 return WINED3D_OK;
748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
749 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
752 IWineD3DStateBlockImpl *object;
753 HRESULT hr;
755 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
756 if(!object)
758 ERR("Failed to allocate stateblock memory.\n");
759 return E_OUTOFMEMORY;
762 hr = stateblock_init(object, This, type);
763 if (FAILED(hr))
765 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
766 HeapFree(GetProcessHeap(), 0, object);
767 return hr;
770 TRACE("Created stateblock %p.\n", object);
771 *stateblock = (IWineD3DStateBlock *)object;
773 return WINED3D_OK;
776 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
777 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
778 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
779 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DSurfaceImpl *object;
783 HRESULT hr;
785 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
786 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
787 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
788 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
789 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
791 if (Impl == SURFACE_OPENGL && !This->adapter)
793 ERR("OpenGL surfaces are not available without OpenGL.\n");
794 return WINED3DERR_NOTAVAILABLE;
797 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
798 if (!object)
800 ERR("Failed to allocate surface memory.\n");
801 return WINED3DERR_OUTOFVIDEOMEMORY;
804 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
805 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
806 if (FAILED(hr))
808 WARN("Failed to initialize surface, returning %#x.\n", hr);
809 HeapFree(GetProcessHeap(), 0, object);
810 return hr;
813 TRACE("(%p) : Created surface %p\n", This, object);
815 *ppSurface = (IWineD3DSurface *)object;
817 return hr;
820 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
821 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
823 struct wined3d_rendertarget_view *object;
825 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
826 if (!object)
828 ERR("Failed to allocate memory\n");
829 return E_OUTOFMEMORY;
832 object->vtbl = &wined3d_rendertarget_view_vtbl;
833 object->refcount = 1;
834 IWineD3DResource_AddRef(resource);
835 object->resource = resource;
836 object->parent = parent;
838 *rendertarget_view = (IWineD3DRendertargetView *)object;
840 return WINED3D_OK;
843 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
844 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
845 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 IWineD3DTextureImpl *object;
849 HRESULT hr;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
855 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
856 if (!object)
858 ERR("Out of memory\n");
859 *ppTexture = NULL;
860 return WINED3DERR_OUTOFVIDEOMEMORY;
863 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
864 if (FAILED(hr))
866 WARN("Failed to initialize texture, returning %#x\n", hr);
867 HeapFree(GetProcessHeap(), 0, object);
868 *ppTexture = NULL;
869 return hr;
872 *ppTexture = (IWineD3DTexture *)object;
874 TRACE("(%p) : Created texture %p\n", This, object);
876 return WINED3D_OK;
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
880 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
881 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
884 IWineD3DVolumeTextureImpl *object;
885 HRESULT hr;
887 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
888 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
890 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
891 if (!object)
893 ERR("Out of memory\n");
894 *ppVolumeTexture = NULL;
895 return WINED3DERR_OUTOFVIDEOMEMORY;
898 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
899 if (FAILED(hr))
901 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
902 HeapFree(GetProcessHeap(), 0, object);
903 *ppVolumeTexture = NULL;
904 return hr;
907 TRACE("(%p) : Created volume texture %p.\n", This, object);
908 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
910 return WINED3D_OK;
913 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
914 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
915 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
918 IWineD3DVolumeImpl *object;
919 HRESULT hr;
921 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
925 if (!object)
927 ERR("Out of memory\n");
928 *ppVolume = NULL;
929 return WINED3DERR_OUTOFVIDEOMEMORY;
932 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
933 if (FAILED(hr))
935 WARN("Failed to initialize volume, returning %#x.\n", hr);
936 HeapFree(GetProcessHeap(), 0, object);
937 return hr;
940 TRACE("(%p) : Created volume %p.\n", This, object);
941 *ppVolume = (IWineD3DVolume *)object;
943 return WINED3D_OK;
946 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
947 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
948 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
951 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
952 HRESULT hr;
954 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
955 if (!object)
957 ERR("Out of memory\n");
958 *ppCubeTexture = NULL;
959 return WINED3DERR_OUTOFVIDEOMEMORY;
962 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
963 if (FAILED(hr))
965 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
966 HeapFree(GetProcessHeap(), 0, object);
967 *ppCubeTexture = NULL;
968 return hr;
971 TRACE("(%p) : Created Cube Texture %p\n", This, object);
972 *ppCubeTexture = (IWineD3DCubeTexture *)object;
974 return WINED3D_OK;
977 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
978 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
981 IWineD3DQueryImpl *object;
982 HRESULT hr;
984 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
986 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
987 if (!object)
989 ERR("Failed to allocate query memory.\n");
990 return E_OUTOFMEMORY;
993 hr = query_init(object, This, type, parent);
994 if (FAILED(hr))
996 WARN("Failed to initialize query, hr %#x.\n", hr);
997 HeapFree(GetProcessHeap(), 0, object);
998 return hr;
1001 TRACE("Created query %p.\n", object);
1002 *query = (IWineD3DQuery *)object;
1004 return WINED3D_OK;
1007 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1008 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1009 IUnknown *parent, WINED3DSURFTYPE surface_type)
1011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1012 IWineD3DSwapChainImpl *object;
1013 HRESULT hr;
1015 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1016 iface, present_parameters, swapchain, parent, surface_type);
1018 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1019 if (!object)
1021 ERR("Failed to allocate swapchain memory.\n");
1022 return E_OUTOFMEMORY;
1025 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1026 if (FAILED(hr))
1028 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1029 HeapFree(GetProcessHeap(), 0, object);
1030 return hr;
1033 TRACE("Created swapchain %p.\n", object);
1034 *swapchain = (IWineD3DSwapChain *)object;
1036 return WINED3D_OK;
1039 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1040 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1042 TRACE("(%p)\n", This);
1044 return This->NumberOfSwapChains;
1047 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1049 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1051 if(iSwapChain < This->NumberOfSwapChains) {
1052 *pSwapChain = This->swapchains[iSwapChain];
1053 IWineD3DSwapChain_AddRef(*pSwapChain);
1054 TRACE("(%p) returning %p\n", This, *pSwapChain);
1055 return WINED3D_OK;
1056 } else {
1057 TRACE("Swapchain out of range\n");
1058 *pSwapChain = NULL;
1059 return WINED3DERR_INVALIDCALL;
1063 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1064 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1065 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1068 IWineD3DVertexDeclarationImpl *object = NULL;
1069 HRESULT hr;
1071 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1072 iface, declaration, parent, elements, element_count);
1074 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1075 if(!object)
1077 ERR("Failed to allocate vertex declaration memory.\n");
1078 return E_OUTOFMEMORY;
1081 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1082 if (FAILED(hr))
1084 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1085 HeapFree(GetProcessHeap(), 0, object);
1086 return hr;
1089 TRACE("Created vertex declaration %p.\n", object);
1090 *declaration = (IWineD3DVertexDeclaration *)object;
1092 return WINED3D_OK;
1095 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1096 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1098 unsigned int idx, idx2;
1099 unsigned int offset;
1100 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1101 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1102 BOOL has_blend_idx = has_blend &&
1103 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1104 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1105 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1106 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1107 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1108 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1109 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1111 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1112 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1113 WINED3DVERTEXELEMENT *elements = NULL;
1115 unsigned int size;
1116 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1117 if (has_blend_idx) num_blends--;
1119 /* Compute declaration size */
1120 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1121 has_psize + has_diffuse + has_specular + num_textures;
1123 /* convert the declaration */
1124 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1125 if (!elements) return ~0U;
1127 idx = 0;
1128 if (has_pos) {
1129 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1130 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1131 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1133 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1134 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1135 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1137 else {
1138 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1139 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1141 elements[idx].usage_idx = 0;
1142 idx++;
1144 if (has_blend && (num_blends > 0)) {
1145 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1146 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1147 else {
1148 switch(num_blends) {
1149 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1150 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1151 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1152 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1153 default:
1154 ERR("Unexpected amount of blend values: %u\n", num_blends);
1157 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1158 elements[idx].usage_idx = 0;
1159 idx++;
1161 if (has_blend_idx) {
1162 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1163 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1164 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1165 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1166 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1167 else
1168 elements[idx].format = WINED3DFMT_R32_FLOAT;
1169 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1170 elements[idx].usage_idx = 0;
1171 idx++;
1173 if (has_normal) {
1174 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1175 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1176 elements[idx].usage_idx = 0;
1177 idx++;
1179 if (has_psize) {
1180 elements[idx].format = WINED3DFMT_R32_FLOAT;
1181 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1182 elements[idx].usage_idx = 0;
1183 idx++;
1185 if (has_diffuse) {
1186 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1187 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1188 elements[idx].usage_idx = 0;
1189 idx++;
1191 if (has_specular) {
1192 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1193 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1194 elements[idx].usage_idx = 1;
1195 idx++;
1197 for (idx2 = 0; idx2 < num_textures; idx2++) {
1198 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1199 switch (numcoords) {
1200 case WINED3DFVF_TEXTUREFORMAT1:
1201 elements[idx].format = WINED3DFMT_R32_FLOAT;
1202 break;
1203 case WINED3DFVF_TEXTUREFORMAT2:
1204 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1205 break;
1206 case WINED3DFVF_TEXTUREFORMAT3:
1207 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1208 break;
1209 case WINED3DFVF_TEXTUREFORMAT4:
1210 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1211 break;
1213 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1214 elements[idx].usage_idx = idx2;
1215 idx++;
1218 /* Now compute offsets, and initialize the rest of the fields */
1219 for (idx = 0, offset = 0; idx < size; ++idx)
1221 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1222 elements[idx].input_slot = 0;
1223 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1224 elements[idx].offset = offset;
1225 offset += format_desc->component_count * format_desc->component_size;
1228 *ppVertexElements = elements;
1229 return size;
1232 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1233 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1234 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1237 WINED3DVERTEXELEMENT *elements;
1238 unsigned int size;
1239 DWORD hr;
1241 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1243 size = ConvertFvfToDeclaration(This, fvf, &elements);
1244 if (size == ~0U) return E_OUTOFMEMORY;
1246 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1247 HeapFree(GetProcessHeap(), 0, elements);
1248 return hr;
1251 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1252 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1253 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1254 const struct wined3d_parent_ops *parent_ops)
1256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1257 IWineD3DVertexShaderImpl *object;
1258 HRESULT hr;
1260 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1261 if (!object)
1263 ERR("Failed to allocate shader memory.\n");
1264 return E_OUTOFMEMORY;
1267 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1268 if (FAILED(hr))
1270 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1271 HeapFree(GetProcessHeap(), 0, object);
1272 return hr;
1275 TRACE("Created vertex shader %p.\n", object);
1276 *ppVertexShader = (IWineD3DVertexShader *)object;
1278 return WINED3D_OK;
1281 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1282 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1283 IWineD3DGeometryShader **shader, IUnknown *parent,
1284 const struct wined3d_parent_ops *parent_ops)
1286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1287 struct wined3d_geometryshader *object;
1288 HRESULT hr;
1290 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1291 if (!object)
1293 ERR("Failed to allocate shader memory.\n");
1294 return E_OUTOFMEMORY;
1297 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1298 if (FAILED(hr))
1300 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1301 HeapFree(GetProcessHeap(), 0, object);
1302 return hr;
1305 TRACE("Created geometry shader %p.\n", object);
1306 *shader = (IWineD3DGeometryShader *)object;
1308 return WINED3D_OK;
1311 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1312 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1313 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1314 const struct wined3d_parent_ops *parent_ops)
1316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 IWineD3DPixelShaderImpl *object;
1318 HRESULT hr;
1320 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1321 if (!object)
1323 ERR("Failed to allocate shader memory.\n");
1324 return E_OUTOFMEMORY;
1327 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1328 if (FAILED(hr))
1330 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1331 HeapFree(GetProcessHeap(), 0, object);
1332 return hr;
1335 TRACE("Created pixel shader %p.\n", object);
1336 *ppPixelShader = (IWineD3DPixelShader *)object;
1338 return WINED3D_OK;
1341 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1342 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1345 IWineD3DPaletteImpl *object;
1346 HRESULT hr;
1347 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1349 /* Create the new object */
1350 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1351 if(!object) {
1352 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1353 return E_OUTOFMEMORY;
1356 object->lpVtbl = &IWineD3DPalette_Vtbl;
1357 object->ref = 1;
1358 object->Flags = Flags;
1359 object->parent = Parent;
1360 object->device = This;
1361 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1362 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1364 if(!object->hpal) {
1365 HeapFree( GetProcessHeap(), 0, object);
1366 return E_OUTOFMEMORY;
1369 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1370 if(FAILED(hr)) {
1371 IWineD3DPalette_Release((IWineD3DPalette *) object);
1372 return hr;
1375 *Palette = (IWineD3DPalette *) object;
1377 return WINED3D_OK;
1380 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1381 HBITMAP hbm;
1382 BITMAP bm;
1383 HRESULT hr;
1384 HDC dcb = NULL, dcs = NULL;
1385 WINEDDCOLORKEY colorkey;
1387 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1388 if(hbm)
1390 GetObjectA(hbm, sizeof(BITMAP), &bm);
1391 dcb = CreateCompatibleDC(NULL);
1392 if(!dcb) goto out;
1393 SelectObject(dcb, hbm);
1395 else
1397 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1398 * couldn't be loaded
1400 memset(&bm, 0, sizeof(bm));
1401 bm.bmWidth = 32;
1402 bm.bmHeight = 32;
1405 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1406 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1407 NULL, &wined3d_null_parent_ops);
1408 if(FAILED(hr)) {
1409 ERR("Wine logo requested, but failed to create surface\n");
1410 goto out;
1413 if(dcb) {
1414 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1415 if(FAILED(hr)) goto out;
1416 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1417 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1419 colorkey.dwColorSpaceLowValue = 0;
1420 colorkey.dwColorSpaceHighValue = 0;
1421 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1422 } else {
1423 /* Fill the surface with a white color to show that wined3d is there */
1424 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1427 out:
1428 if (dcb) DeleteDC(dcb);
1429 if (hbm) DeleteObject(hbm);
1432 /* Context activation is done by the caller. */
1433 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1435 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1436 unsigned int i;
1437 /* Under DirectX you can have texture stage operations even if no texture is
1438 bound, whereas opengl will only do texture operations when a valid texture is
1439 bound. We emulate this by creating dummy textures and binding them to each
1440 texture stage, but disable all stages by default. Hence if a stage is enabled
1441 then the default texture will kick in until replaced by a SetTexture call */
1442 ENTER_GL();
1444 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1446 /* The dummy texture does not have client storage backing */
1447 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1448 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1451 for (i = 0; i < gl_info->limits.textures; ++i)
1453 GLubyte white = 255;
1455 /* Make appropriate texture active */
1456 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1457 checkGLcall("glActiveTextureARB");
1459 /* Generate an opengl texture name */
1460 glGenTextures(1, &This->dummyTextureName[i]);
1461 checkGLcall("glGenTextures");
1462 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1464 /* Generate a dummy 2d texture (not using 1d because they cause many
1465 * DRI drivers fall back to sw) */
1466 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1467 checkGLcall("glBindTexture");
1469 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1470 checkGLcall("glTexImage2D");
1473 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1475 /* Reenable because if supported it is enabled by default */
1476 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1477 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1480 LEAVE_GL();
1483 /* Context activation is done by the caller. */
1484 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1486 ENTER_GL();
1487 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1488 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1489 LEAVE_GL();
1491 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1494 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1496 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1498 if (!wined3d_register_window(window, device))
1500 ERR("Failed to register window %p.\n", window);
1501 return E_FAIL;
1504 device->focus_window = window;
1505 SetForegroundWindow(window);
1507 return WINED3D_OK;
1510 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1512 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1514 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1515 device->focus_window = NULL;
1518 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1519 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1522 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1523 IWineD3DSwapChainImpl *swapchain = NULL;
1524 struct wined3d_context *context;
1525 HRESULT hr;
1526 DWORD state;
1527 unsigned int i;
1529 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1531 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1532 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1534 TRACE("(%p) : Creating stateblock\n", This);
1535 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1536 hr = IWineD3DDevice_CreateStateBlock(iface,
1537 WINED3DSBT_INIT,
1538 (IWineD3DStateBlock **)&This->stateBlock,
1539 NULL);
1540 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1541 WARN("Failed to create stateblock\n");
1542 goto err_out;
1544 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1545 This->updateStateBlock = This->stateBlock;
1546 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1548 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1549 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1550 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1551 sizeof(GLenum) * gl_info->limits.buffers);
1553 This->NumberOfPalettes = 1;
1554 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1555 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1556 ERR("Out of memory!\n");
1557 hr = E_OUTOFMEMORY;
1558 goto err_out;
1560 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1561 if(!This->palettes[0]) {
1562 ERR("Out of memory!\n");
1563 hr = E_OUTOFMEMORY;
1564 goto err_out;
1566 for (i = 0; i < 256; ++i) {
1567 This->palettes[0][i].peRed = 0xFF;
1568 This->palettes[0][i].peGreen = 0xFF;
1569 This->palettes[0][i].peBlue = 0xFF;
1570 This->palettes[0][i].peFlags = 0xFF;
1572 This->currentPalette = 0;
1574 /* Initialize the texture unit mapping to a 1:1 mapping */
1575 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1577 if (state < gl_info->limits.fragment_samplers)
1579 This->texUnitMap[state] = state;
1580 This->rev_tex_unit_map[state] = state;
1581 } else {
1582 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1583 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1587 /* Setup the implicit swapchain. This also initializes a context. */
1588 TRACE("Creating implicit swapchain\n");
1589 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1590 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1591 if (FAILED(hr))
1593 WARN("Failed to create implicit swapchain\n");
1594 goto err_out;
1597 This->NumberOfSwapChains = 1;
1598 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1599 if(!This->swapchains) {
1600 ERR("Out of memory!\n");
1601 goto err_out;
1603 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1605 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1606 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1607 This->render_targets[0] = swapchain->backBuffer[0];
1609 else {
1610 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1611 This->render_targets[0] = swapchain->frontBuffer;
1613 IWineD3DSurface_AddRef(This->render_targets[0]);
1615 /* Depth Stencil support */
1616 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1617 if (NULL != This->stencilBufferTarget) {
1618 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1621 hr = This->shader_backend->shader_alloc_private(iface);
1622 if(FAILED(hr)) {
1623 TRACE("Shader private data couldn't be allocated\n");
1624 goto err_out;
1626 hr = This->frag_pipe->alloc_private(iface);
1627 if(FAILED(hr)) {
1628 TRACE("Fragment pipeline private data couldn't be allocated\n");
1629 goto err_out;
1631 hr = This->blitter->alloc_private(iface);
1632 if(FAILED(hr)) {
1633 TRACE("Blitter private data couldn't be allocated\n");
1634 goto err_out;
1637 /* Set up some starting GL setup */
1639 /* Setup all the devices defaults */
1640 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1642 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1644 create_dummy_textures(This);
1646 ENTER_GL();
1648 /* Initialize the current view state */
1649 This->view_ident = 1;
1650 This->contexts[0]->last_was_rhw = 0;
1651 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1652 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1654 switch(wined3d_settings.offscreen_rendering_mode) {
1655 case ORM_FBO:
1656 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1657 break;
1659 case ORM_BACKBUFFER:
1661 if (context_get_current()->aux_buffers > 0)
1663 TRACE("Using auxilliary buffer for offscreen rendering\n");
1664 This->offscreenBuffer = GL_AUX0;
1665 } else {
1666 TRACE("Using back buffer for offscreen rendering\n");
1667 This->offscreenBuffer = GL_BACK;
1672 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1673 LEAVE_GL();
1675 context_release(context);
1677 /* Clear the screen */
1678 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1679 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1680 0x00, 1.0f, 0);
1682 This->d3d_initialized = TRUE;
1684 if(wined3d_settings.logo) {
1685 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1687 This->highest_dirty_ps_const = 0;
1688 This->highest_dirty_vs_const = 0;
1689 return WINED3D_OK;
1691 err_out:
1692 HeapFree(GetProcessHeap(), 0, This->render_targets);
1693 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1694 HeapFree(GetProcessHeap(), 0, This->swapchains);
1695 This->NumberOfSwapChains = 0;
1696 if(This->palettes) {
1697 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1698 HeapFree(GetProcessHeap(), 0, This->palettes);
1700 This->NumberOfPalettes = 0;
1701 if(swapchain) {
1702 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1704 if(This->stateBlock) {
1705 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1706 This->stateBlock = NULL;
1708 if (This->blit_priv) {
1709 This->blitter->free_private(iface);
1711 if (This->fragment_priv) {
1712 This->frag_pipe->free_private(iface);
1714 if (This->shader_priv) {
1715 This->shader_backend->shader_free_private(iface);
1717 return hr;
1720 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1721 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1724 IWineD3DSwapChainImpl *swapchain = NULL;
1725 HRESULT hr;
1727 /* Setup the implicit swapchain */
1728 TRACE("Creating implicit swapchain\n");
1729 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1730 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1731 if (FAILED(hr))
1733 WARN("Failed to create implicit swapchain\n");
1734 goto err_out;
1737 This->NumberOfSwapChains = 1;
1738 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1739 if(!This->swapchains) {
1740 ERR("Out of memory!\n");
1741 goto err_out;
1743 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1744 return WINED3D_OK;
1746 err_out:
1747 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1748 return hr;
1751 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1753 IWineD3DResource_UnLoad(resource);
1754 IWineD3DResource_Release(resource);
1755 return WINED3D_OK;
1758 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1759 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1762 const struct wined3d_gl_info *gl_info;
1763 struct wined3d_context *context;
1764 int sampler;
1765 UINT i;
1766 TRACE("(%p)\n", This);
1768 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1770 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1771 * it was created. Thus make sure a context is active for the glDelete* calls
1773 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1774 gl_info = context->gl_info;
1776 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1778 /* Unload resources */
1779 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1781 TRACE("Deleting high order patches\n");
1782 for(i = 0; i < PATCHMAP_SIZE; i++) {
1783 struct list *e1, *e2;
1784 struct WineD3DRectPatch *patch;
1785 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1786 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1787 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1791 /* Delete the mouse cursor texture */
1792 if(This->cursorTexture) {
1793 ENTER_GL();
1794 glDeleteTextures(1, &This->cursorTexture);
1795 LEAVE_GL();
1796 This->cursorTexture = 0;
1799 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1800 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1802 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1803 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1806 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1807 * private data, it might contain opengl pointers
1809 if(This->depth_blt_texture) {
1810 ENTER_GL();
1811 glDeleteTextures(1, &This->depth_blt_texture);
1812 LEAVE_GL();
1813 This->depth_blt_texture = 0;
1815 if (This->depth_blt_rb) {
1816 ENTER_GL();
1817 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1818 LEAVE_GL();
1819 This->depth_blt_rb = 0;
1820 This->depth_blt_rb_w = 0;
1821 This->depth_blt_rb_h = 0;
1824 /* Release the update stateblock */
1825 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1826 if(This->updateStateBlock != This->stateBlock)
1827 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1829 This->updateStateBlock = NULL;
1831 { /* because were not doing proper internal refcounts releasing the primary state block
1832 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1833 to set this->stateBlock = NULL; first */
1834 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1835 This->stateBlock = NULL;
1837 /* Release the stateblock */
1838 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1839 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1843 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1844 This->blitter->free_private(iface);
1845 This->frag_pipe->free_private(iface);
1846 This->shader_backend->shader_free_private(iface);
1848 /* Release the buffers (with sanity checks)*/
1849 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1850 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1851 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1852 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1854 This->stencilBufferTarget = NULL;
1856 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1857 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1858 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1860 TRACE("Setting rendertarget to NULL\n");
1861 This->render_targets[0] = NULL;
1863 if (This->auto_depth_stencil_buffer) {
1864 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1866 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1868 This->auto_depth_stencil_buffer = NULL;
1871 context_release(context);
1873 for(i=0; i < This->NumberOfSwapChains; i++) {
1874 TRACE("Releasing the implicit swapchain %d\n", i);
1875 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1876 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1880 HeapFree(GetProcessHeap(), 0, This->swapchains);
1881 This->swapchains = NULL;
1882 This->NumberOfSwapChains = 0;
1884 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1885 HeapFree(GetProcessHeap(), 0, This->palettes);
1886 This->palettes = NULL;
1887 This->NumberOfPalettes = 0;
1889 HeapFree(GetProcessHeap(), 0, This->render_targets);
1890 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1891 This->render_targets = NULL;
1892 This->draw_buffers = NULL;
1894 This->d3d_initialized = FALSE;
1896 return WINED3D_OK;
1899 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1901 unsigned int i;
1903 for(i=0; i < This->NumberOfSwapChains; i++) {
1904 TRACE("Releasing the implicit swapchain %d\n", i);
1905 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1906 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1910 HeapFree(GetProcessHeap(), 0, This->swapchains);
1911 This->swapchains = NULL;
1912 This->NumberOfSwapChains = 0;
1913 return WINED3D_OK;
1916 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1917 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1918 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1920 * There is no way to deactivate thread safety once it is enabled.
1922 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1925 /*For now just store the flag(needed in case of ddraw) */
1926 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1929 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1930 const WINED3DDISPLAYMODE* pMode) {
1931 DEVMODEW devmode;
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1933 LONG ret;
1934 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1935 RECT clip_rc;
1937 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1939 /* Resize the screen even without a window:
1940 * The app could have unset it with SetCooperativeLevel, but not called
1941 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1942 * but we don't have any hwnd
1945 memset(&devmode, 0, sizeof(devmode));
1946 devmode.dmSize = sizeof(devmode);
1947 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1948 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1949 devmode.dmPelsWidth = pMode->Width;
1950 devmode.dmPelsHeight = pMode->Height;
1952 devmode.dmDisplayFrequency = pMode->RefreshRate;
1953 if (pMode->RefreshRate != 0) {
1954 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1957 /* Only change the mode if necessary */
1958 if( (This->ddraw_width == pMode->Width) &&
1959 (This->ddraw_height == pMode->Height) &&
1960 (This->ddraw_format == pMode->Format) &&
1961 (pMode->RefreshRate == 0) ) {
1962 return WINED3D_OK;
1965 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1966 if (ret != DISP_CHANGE_SUCCESSFUL) {
1967 if(devmode.dmDisplayFrequency != 0) {
1968 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1969 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1970 devmode.dmDisplayFrequency = 0;
1971 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1973 if(ret != DISP_CHANGE_SUCCESSFUL) {
1974 return WINED3DERR_NOTAVAILABLE;
1978 /* Store the new values */
1979 This->ddraw_width = pMode->Width;
1980 This->ddraw_height = pMode->Height;
1981 This->ddraw_format = pMode->Format;
1983 /* And finally clip mouse to our screen */
1984 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1985 ClipCursor(&clip_rc);
1987 return WINED3D_OK;
1990 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1992 *ppD3D = This->wined3d;
1993 TRACE("Returning %p.\n", *ppD3D);
1994 IWineD3D_AddRef(*ppD3D);
1995 return WINED3D_OK;
1998 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2001 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2002 (This->adapter->TextureRam/(1024*1024)),
2003 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2004 /* return simulated texture memory left */
2005 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2008 /*****
2009 * Get / Set Stream Source
2010 *****/
2011 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2012 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015 IWineD3DBuffer *oldSrc;
2017 if (StreamNumber >= MAX_STREAMS) {
2018 WARN("Stream out of range %d\n", StreamNumber);
2019 return WINED3DERR_INVALIDCALL;
2020 } else if(OffsetInBytes & 0x3) {
2021 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2022 return WINED3DERR_INVALIDCALL;
2025 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2026 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2028 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2030 if(oldSrc == pStreamData &&
2031 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2032 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2033 TRACE("Application is setting the old values over, nothing to do\n");
2034 return WINED3D_OK;
2037 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2038 if (pStreamData) {
2039 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2040 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2043 /* Handle recording of state blocks */
2044 if (This->isRecordingState) {
2045 TRACE("Recording... not performing anything\n");
2046 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2047 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2048 return WINED3D_OK;
2051 if (pStreamData != NULL) {
2052 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2053 IWineD3DBuffer_AddRef(pStreamData);
2055 if (oldSrc != NULL) {
2056 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2057 IWineD3DBuffer_Release(oldSrc);
2060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2062 return WINED3D_OK;
2065 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2066 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2070 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2071 This->stateBlock->streamSource[StreamNumber],
2072 This->stateBlock->streamOffset[StreamNumber],
2073 This->stateBlock->streamStride[StreamNumber]);
2075 if (StreamNumber >= MAX_STREAMS) {
2076 WARN("Stream out of range %d\n", StreamNumber);
2077 return WINED3DERR_INVALIDCALL;
2079 *pStream = This->stateBlock->streamSource[StreamNumber];
2080 *pStride = This->stateBlock->streamStride[StreamNumber];
2081 if (pOffset) {
2082 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2085 if (*pStream != NULL) {
2086 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2088 return WINED3D_OK;
2091 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2094 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2096 /* Verify input at least in d3d9 this is invalid*/
2097 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2098 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2099 return WINED3DERR_INVALIDCALL;
2101 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2102 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2103 return WINED3DERR_INVALIDCALL;
2105 if( Divider == 0 ){
2106 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2107 return WINED3DERR_INVALIDCALL;
2110 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2111 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2113 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2114 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2116 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2117 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2121 return WINED3D_OK;
2124 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2128 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2130 TRACE("(%p) : returning %d\n", This, *Divider);
2132 return WINED3D_OK;
2135 /*****
2136 * Get / Set & Multiply Transform
2137 *****/
2138 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2141 /* Most of this routine, comments included copied from ddraw tree initially: */
2142 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2144 /* Handle recording of state blocks */
2145 if (This->isRecordingState) {
2146 TRACE("Recording... not performing anything\n");
2147 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2148 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2149 return WINED3D_OK;
2153 * If the new matrix is the same as the current one,
2154 * we cut off any further processing. this seems to be a reasonable
2155 * optimization because as was noticed, some apps (warcraft3 for example)
2156 * tend towards setting the same matrix repeatedly for some reason.
2158 * From here on we assume that the new matrix is different, wherever it matters.
2160 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2161 TRACE("The app is setting the same matrix over again\n");
2162 return WINED3D_OK;
2163 } else {
2164 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2168 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2169 where ViewMat = Camera space, WorldMat = world space.
2171 In OpenGL, camera and world space is combined into GL_MODELVIEW
2172 matrix. The Projection matrix stay projection matrix.
2175 /* Capture the times we can just ignore the change for now */
2176 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2177 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2178 /* Handled by the state manager */
2181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2182 return WINED3D_OK;
2185 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2188 *pMatrix = This->stateBlock->transforms[State];
2189 return WINED3D_OK;
2192 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2193 const WINED3DMATRIX *mat = NULL;
2194 WINED3DMATRIX temp;
2196 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2197 * below means it will be recorded in a state block change, but it
2198 * works regardless where it is recorded.
2199 * If this is found to be wrong, change to StateBlock.
2201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2202 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2204 if (State <= HIGHEST_TRANSFORMSTATE)
2206 mat = &This->updateStateBlock->transforms[State];
2207 } else {
2208 FIXME("Unhandled transform state!!\n");
2211 multiply_matrix(&temp, mat, pMatrix);
2213 /* Apply change via set transform - will reapply to eg. lights this way */
2214 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2217 /*****
2218 * Get / Set Light
2219 *****/
2220 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2221 you can reference any indexes you want as long as that number max are enabled at any
2222 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2223 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2224 but when recording, just build a chain pretty much of commands to be replayed. */
2226 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2227 float rho;
2228 struct wined3d_light_info *object = NULL;
2229 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2230 struct list *e;
2232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2233 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2235 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2236 * the gl driver.
2238 if(!pLight) {
2239 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2240 return WINED3DERR_INVALIDCALL;
2243 switch(pLight->Type) {
2244 case WINED3DLIGHT_POINT:
2245 case WINED3DLIGHT_SPOT:
2246 case WINED3DLIGHT_PARALLELPOINT:
2247 case WINED3DLIGHT_GLSPOT:
2248 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2249 * most wanted
2251 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2253 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2254 return WINED3DERR_INVALIDCALL;
2256 break;
2258 case WINED3DLIGHT_DIRECTIONAL:
2259 /* Ignores attenuation */
2260 break;
2262 default:
2263 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2264 return WINED3DERR_INVALIDCALL;
2267 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2269 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2270 if(object->OriginalIndex == Index) break;
2271 object = NULL;
2274 if(!object) {
2275 TRACE("Adding new light\n");
2276 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2277 if(!object) {
2278 ERR("Out of memory error when allocating a light\n");
2279 return E_OUTOFMEMORY;
2281 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2282 object->glIndex = -1;
2283 object->OriginalIndex = Index;
2286 /* Initialize the object */
2287 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,
2288 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2289 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2290 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2291 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2292 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2293 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2295 /* Save away the information */
2296 object->OriginalParms = *pLight;
2298 switch (pLight->Type) {
2299 case WINED3DLIGHT_POINT:
2300 /* Position */
2301 object->lightPosn[0] = pLight->Position.x;
2302 object->lightPosn[1] = pLight->Position.y;
2303 object->lightPosn[2] = pLight->Position.z;
2304 object->lightPosn[3] = 1.0f;
2305 object->cutoff = 180.0f;
2306 /* FIXME: Range */
2307 break;
2309 case WINED3DLIGHT_DIRECTIONAL:
2310 /* Direction */
2311 object->lightPosn[0] = -pLight->Direction.x;
2312 object->lightPosn[1] = -pLight->Direction.y;
2313 object->lightPosn[2] = -pLight->Direction.z;
2314 object->lightPosn[3] = 0.0f;
2315 object->exponent = 0.0f;
2316 object->cutoff = 180.0f;
2317 break;
2319 case WINED3DLIGHT_SPOT:
2320 /* Position */
2321 object->lightPosn[0] = pLight->Position.x;
2322 object->lightPosn[1] = pLight->Position.y;
2323 object->lightPosn[2] = pLight->Position.z;
2324 object->lightPosn[3] = 1.0f;
2326 /* Direction */
2327 object->lightDirn[0] = pLight->Direction.x;
2328 object->lightDirn[1] = pLight->Direction.y;
2329 object->lightDirn[2] = pLight->Direction.z;
2330 object->lightDirn[3] = 1.0f;
2333 * opengl-ish and d3d-ish spot lights use too different models for the
2334 * light "intensity" as a function of the angle towards the main light direction,
2335 * so we only can approximate very roughly.
2336 * however spot lights are rather rarely used in games (if ever used at all).
2337 * furthermore if still used, probably nobody pays attention to such details.
2339 if (pLight->Falloff == 0) {
2340 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2341 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2342 * will always be 1.0 for both of them, and we don't have to care for the
2343 * rest of the rather complex calculation
2345 object->exponent = 0.0f;
2346 } else {
2347 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2348 if (rho < 0.0001f) rho = 0.0001f;
2349 object->exponent = -0.3f/logf(cosf(rho/2));
2351 if (object->exponent > 128.0f)
2353 object->exponent = 128.0f;
2355 object->cutoff = pLight->Phi*90/M_PI;
2357 /* FIXME: Range */
2358 break;
2360 default:
2361 FIXME("Unrecognized light type %d\n", pLight->Type);
2364 /* Update the live definitions if the light is currently assigned a glIndex */
2365 if (object->glIndex != -1 && !This->isRecordingState) {
2366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2368 return WINED3D_OK;
2371 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2373 struct wined3d_light_info *lightInfo = NULL;
2374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2376 struct list *e;
2377 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2379 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2381 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2382 if(lightInfo->OriginalIndex == Index) break;
2383 lightInfo = NULL;
2386 if (lightInfo == NULL) {
2387 TRACE("Light information requested but light not defined\n");
2388 return WINED3DERR_INVALIDCALL;
2391 *pLight = lightInfo->OriginalParms;
2392 return WINED3D_OK;
2395 /*****
2396 * Get / Set Light Enable
2397 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2398 *****/
2399 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2401 struct wined3d_light_info *lightInfo = NULL;
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2404 struct list *e;
2405 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2407 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2409 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2410 if(lightInfo->OriginalIndex == Index) break;
2411 lightInfo = NULL;
2413 TRACE("Found light: %p\n", lightInfo);
2415 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2416 if (lightInfo == NULL) {
2418 TRACE("Light enabled requested but light not defined, so defining one!\n");
2419 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2421 /* Search for it again! Should be fairly quick as near head of list */
2422 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2424 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2425 if(lightInfo->OriginalIndex == Index) break;
2426 lightInfo = NULL;
2428 if (lightInfo == NULL) {
2429 FIXME("Adding default lights has failed dismally\n");
2430 return WINED3DERR_INVALIDCALL;
2434 if(!Enable) {
2435 if(lightInfo->glIndex != -1) {
2436 if(!This->isRecordingState) {
2437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2440 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2441 lightInfo->glIndex = -1;
2442 } else {
2443 TRACE("Light already disabled, nothing to do\n");
2445 lightInfo->enabled = FALSE;
2446 } else {
2447 lightInfo->enabled = TRUE;
2448 if (lightInfo->glIndex != -1) {
2449 /* nop */
2450 TRACE("Nothing to do as light was enabled\n");
2451 } else {
2452 int i;
2453 /* Find a free gl light */
2454 for(i = 0; i < This->maxConcurrentLights; i++) {
2455 if(This->updateStateBlock->activeLights[i] == NULL) {
2456 This->updateStateBlock->activeLights[i] = lightInfo;
2457 lightInfo->glIndex = i;
2458 break;
2461 if(lightInfo->glIndex == -1) {
2462 /* Our tests show that Windows returns D3D_OK in this situation, even with
2463 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2464 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2465 * as well for those lights.
2467 * TODO: Test how this affects rendering
2469 WARN("Too many concurrently active lights\n");
2470 return WINED3D_OK;
2473 /* i == lightInfo->glIndex */
2474 if(!This->isRecordingState) {
2475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2480 return WINED3D_OK;
2483 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2485 struct wined3d_light_info *lightInfo = NULL;
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 struct list *e;
2488 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2489 TRACE("(%p) : for idx(%d)\n", This, Index);
2491 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2493 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2494 if(lightInfo->OriginalIndex == Index) break;
2495 lightInfo = NULL;
2498 if (lightInfo == NULL) {
2499 TRACE("Light enabled state requested but light not defined\n");
2500 return WINED3DERR_INVALIDCALL;
2502 /* true is 128 according to SetLightEnable */
2503 *pEnable = lightInfo->enabled ? 128 : 0;
2504 return WINED3D_OK;
2507 /*****
2508 * Get / Set Clip Planes
2509 *****/
2510 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2512 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2514 /* Validate Index */
2515 if (Index >= This->adapter->gl_info.limits.clipplanes)
2517 TRACE("Application has requested clipplane this device doesn't support\n");
2518 return WINED3DERR_INVALIDCALL;
2521 This->updateStateBlock->changed.clipplane |= 1 << Index;
2523 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2524 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2525 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2526 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2527 TRACE("Application is setting old values over, nothing to do\n");
2528 return WINED3D_OK;
2531 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2532 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2533 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2534 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2536 /* Handle recording of state blocks */
2537 if (This->isRecordingState) {
2538 TRACE("Recording... not performing anything\n");
2539 return WINED3D_OK;
2542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2544 return WINED3D_OK;
2547 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 TRACE("(%p) : for idx %d\n", This, Index);
2551 /* Validate Index */
2552 if (Index >= This->adapter->gl_info.limits.clipplanes)
2554 TRACE("Application has requested clipplane this device doesn't support\n");
2555 return WINED3DERR_INVALIDCALL;
2558 pPlane[0] = This->stateBlock->clipplane[Index][0];
2559 pPlane[1] = This->stateBlock->clipplane[Index][1];
2560 pPlane[2] = This->stateBlock->clipplane[Index][2];
2561 pPlane[3] = This->stateBlock->clipplane[Index][3];
2562 return WINED3D_OK;
2565 /*****
2566 * Get / Set Clip Plane Status
2567 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2568 *****/
2569 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 FIXME("(%p) : stub\n", This);
2572 if (NULL == pClipStatus) {
2573 return WINED3DERR_INVALIDCALL;
2575 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2576 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2577 return WINED3D_OK;
2580 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 FIXME("(%p) : stub\n", This);
2583 if (NULL == pClipStatus) {
2584 return WINED3DERR_INVALIDCALL;
2586 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2587 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2588 return WINED3D_OK;
2591 /*****
2592 * Get / Set Material
2593 *****/
2594 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2597 This->updateStateBlock->changed.material = TRUE;
2598 This->updateStateBlock->material = *pMaterial;
2600 /* Handle recording of state blocks */
2601 if (This->isRecordingState) {
2602 TRACE("Recording... not performing anything\n");
2603 return WINED3D_OK;
2606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2607 return WINED3D_OK;
2610 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 *pMaterial = This->updateStateBlock->material;
2613 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2614 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2615 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2616 pMaterial->Ambient.b, pMaterial->Ambient.a);
2617 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2618 pMaterial->Specular.b, pMaterial->Specular.a);
2619 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2620 pMaterial->Emissive.b, pMaterial->Emissive.a);
2621 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2623 return WINED3D_OK;
2626 /*****
2627 * Get / Set Indices
2628 *****/
2629 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2630 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 IWineD3DBuffer *oldIdxs;
2635 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2636 oldIdxs = This->updateStateBlock->pIndexData;
2638 This->updateStateBlock->changed.indices = TRUE;
2639 This->updateStateBlock->pIndexData = pIndexData;
2640 This->updateStateBlock->IndexFmt = fmt;
2642 /* Handle recording of state blocks */
2643 if (This->isRecordingState) {
2644 TRACE("Recording... not performing anything\n");
2645 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2646 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2647 return WINED3D_OK;
2650 if(oldIdxs != pIndexData) {
2651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2652 if(pIndexData) {
2653 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2654 IWineD3DBuffer_AddRef(pIndexData);
2656 if(oldIdxs) {
2657 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2658 IWineD3DBuffer_Release(oldIdxs);
2662 return WINED3D_OK;
2665 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 *ppIndexData = This->stateBlock->pIndexData;
2671 /* up ref count on ppindexdata */
2672 if (*ppIndexData) {
2673 IWineD3DBuffer_AddRef(*ppIndexData);
2674 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2675 }else{
2676 TRACE("(%p) No index data set\n", This);
2678 TRACE("Returning %p\n", *ppIndexData);
2680 return WINED3D_OK;
2683 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2684 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 TRACE("(%p)->(%d)\n", This, BaseIndex);
2688 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2689 TRACE("Application is setting the old value over, nothing to do\n");
2690 return WINED3D_OK;
2693 This->updateStateBlock->baseVertexIndex = BaseIndex;
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2699 /* The base vertex index affects the stream sources */
2700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2701 return WINED3D_OK;
2704 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2706 TRACE("(%p) : base_index %p\n", This, base_index);
2708 *base_index = This->stateBlock->baseVertexIndex;
2710 TRACE("Returning %u\n", *base_index);
2712 return WINED3D_OK;
2715 /*****
2716 * Get / Set Viewports
2717 *****/
2718 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p)\n", This);
2722 This->updateStateBlock->changed.viewport = TRUE;
2723 This->updateStateBlock->viewport = *pViewport;
2725 /* Handle recording of state blocks */
2726 if (This->isRecordingState) {
2727 TRACE("Recording... not performing anything\n");
2728 return WINED3D_OK;
2731 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2732 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2735 return WINED3D_OK;
2739 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 TRACE("(%p)\n", This);
2742 *pViewport = This->stateBlock->viewport;
2743 return WINED3D_OK;
2746 /*****
2747 * Get / Set Render States
2748 * TODO: Verify against dx9 definitions
2749 *****/
2750 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 DWORD oldValue = This->stateBlock->renderState[State];
2755 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2757 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2758 This->updateStateBlock->renderState[State] = Value;
2760 /* Handle recording of state blocks */
2761 if (This->isRecordingState) {
2762 TRACE("Recording... not performing anything\n");
2763 return WINED3D_OK;
2766 /* Compared here and not before the assignment to allow proper stateblock recording */
2767 if(Value == oldValue) {
2768 TRACE("Application is setting the old value over, nothing to do\n");
2769 } else {
2770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2779 *pValue = This->stateBlock->renderState[State];
2780 return WINED3D_OK;
2783 /*****
2784 * Get / Set Sampler States
2785 * TODO: Verify against dx9 definitions
2786 *****/
2788 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2790 DWORD oldValue;
2792 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2793 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2795 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2796 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2799 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2800 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2801 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2804 * SetSampler is designed to allow for more than the standard up to 8 textures
2805 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2806 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2808 * http://developer.nvidia.com/object/General_FAQ.html#t6
2810 * There are two new settings for GForce
2811 * the sampler one:
2812 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2813 * and the texture one:
2814 * GL_MAX_TEXTURE_COORDS_ARB.
2815 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2816 ******************/
2818 oldValue = This->stateBlock->samplerState[Sampler][Type];
2819 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2820 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2822 /* Handle recording of state blocks */
2823 if (This->isRecordingState) {
2824 TRACE("Recording... not performing anything\n");
2825 return WINED3D_OK;
2828 if(oldValue == Value) {
2829 TRACE("Application is setting the old value over, nothing to do\n");
2830 return WINED3D_OK;
2833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2835 return WINED3D_OK;
2838 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2841 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2842 This, Sampler, debug_d3dsamplerstate(Type), Type);
2844 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2845 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2848 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2849 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2850 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2852 *Value = This->stateBlock->samplerState[Sampler][Type];
2853 TRACE("(%p) : Returning %#x\n", This, *Value);
2855 return WINED3D_OK;
2858 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2861 This->updateStateBlock->changed.scissorRect = TRUE;
2862 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2863 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2864 return WINED3D_OK;
2866 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2868 if(This->isRecordingState) {
2869 TRACE("Recording... not performing anything\n");
2870 return WINED3D_OK;
2873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2875 return WINED3D_OK;
2878 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 *pRect = This->updateStateBlock->scissorRect;
2882 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2883 return WINED3D_OK;
2886 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2888 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2890 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2892 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2893 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2895 This->updateStateBlock->vertexDecl = pDecl;
2896 This->updateStateBlock->changed.vertexDecl = TRUE;
2898 if (This->isRecordingState) {
2899 TRACE("Recording... not performing anything\n");
2900 return WINED3D_OK;
2901 } else if(pDecl == oldDecl) {
2902 /* Checked after the assignment to allow proper stateblock recording */
2903 TRACE("Application is setting the old declaration over, nothing to do\n");
2904 return WINED3D_OK;
2907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2908 return WINED3D_OK;
2911 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2916 *ppDecl = This->stateBlock->vertexDecl;
2917 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2918 return WINED3D_OK;
2921 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2925 This->updateStateBlock->vertexShader = pShader;
2926 This->updateStateBlock->changed.vertexShader = TRUE;
2928 if (This->isRecordingState) {
2929 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2930 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2931 TRACE("Recording... not performing anything\n");
2932 return WINED3D_OK;
2933 } else if(oldShader == pShader) {
2934 /* Checked here to allow proper stateblock recording */
2935 TRACE("App is setting the old shader over, nothing to do\n");
2936 return WINED3D_OK;
2939 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2940 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2941 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2945 return WINED3D_OK;
2948 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 if (NULL == ppShader) {
2952 return WINED3DERR_INVALIDCALL;
2954 *ppShader = This->stateBlock->vertexShader;
2955 if( NULL != *ppShader)
2956 IWineD3DVertexShader_AddRef(*ppShader);
2958 TRACE("(%p) : returning %p\n", This, *ppShader);
2959 return WINED3D_OK;
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2963 IWineD3DDevice *iface,
2964 UINT start,
2965 CONST BOOL *srcData,
2966 UINT count) {
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2969 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2971 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2972 iface, srcData, start, count);
2974 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2976 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2977 for (i = 0; i < cnt; i++)
2978 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2980 for (i = start; i < cnt + start; ++i) {
2981 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2984 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2986 return WINED3D_OK;
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2990 IWineD3DDevice *iface,
2991 UINT start,
2992 BOOL *dstData,
2993 UINT count) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 int cnt = min(count, MAX_CONST_B - start);
2998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2999 iface, dstData, start, count);
3001 if (dstData == NULL || cnt < 0)
3002 return WINED3DERR_INVALIDCALL;
3004 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3005 return WINED3D_OK;
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3009 IWineD3DDevice *iface,
3010 UINT start,
3011 CONST int *srcData,
3012 UINT count) {
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3017 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3018 iface, srcData, start, count);
3020 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3022 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3023 for (i = 0; i < cnt; i++)
3024 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3025 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3027 for (i = start; i < cnt + start; ++i) {
3028 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3031 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3037 IWineD3DDevice *iface,
3038 UINT start,
3039 int *dstData,
3040 UINT count) {
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 int cnt = min(count, MAX_CONST_I - start);
3045 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3046 iface, dstData, start, count);
3048 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3049 return WINED3DERR_INVALIDCALL;
3051 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3052 return WINED3D_OK;
3055 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3056 IWineD3DDevice *iface,
3057 UINT start,
3058 CONST float *srcData,
3059 UINT count) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3062 UINT i;
3064 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3065 iface, srcData, start, count);
3067 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3068 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3069 return WINED3DERR_INVALIDCALL;
3071 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3072 if(TRACE_ON(d3d)) {
3073 for (i = 0; i < count; i++)
3074 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3075 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3078 if (!This->isRecordingState)
3080 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3084 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3085 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3087 return WINED3D_OK;
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3091 IWineD3DDevice *iface,
3092 UINT start,
3093 float *dstData,
3094 UINT count) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 int cnt = min(count, This->d3d_vshader_constantF - start);
3099 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3100 iface, dstData, start, count);
3102 if (dstData == NULL || cnt < 0)
3103 return WINED3DERR_INVALIDCALL;
3105 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3106 return WINED3D_OK;
3109 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3110 DWORD i;
3111 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3117 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3119 DWORD i = This->rev_tex_unit_map[unit];
3120 DWORD j = This->texUnitMap[stage];
3122 This->texUnitMap[stage] = unit;
3123 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3125 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3128 This->rev_tex_unit_map[unit] = stage;
3129 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3131 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3135 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3136 int i;
3138 This->fixed_function_usage_map = 0;
3139 for (i = 0; i < MAX_TEXTURES; ++i) {
3140 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3141 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3142 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3143 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3144 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3145 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3146 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3147 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3149 if (color_op == WINED3DTOP_DISABLE) {
3150 /* Not used, and disable higher stages */
3151 break;
3154 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3155 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3156 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3157 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3158 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3159 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3160 This->fixed_function_usage_map |= (1 << i);
3163 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3164 This->fixed_function_usage_map |= (1 << (i + 1));
3169 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3171 unsigned int i, tex;
3172 WORD ffu_map;
3174 device_update_fixed_function_usage_map(This);
3175 ffu_map = This->fixed_function_usage_map;
3177 if (This->max_ffp_textures == gl_info->limits.texture_stages
3178 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3180 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3182 if (!(ffu_map & 1)) continue;
3184 if (This->texUnitMap[i] != i) {
3185 device_map_stage(This, i, i);
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3187 markTextureStagesDirty(This, i);
3190 return;
3193 /* Now work out the mapping */
3194 tex = 0;
3195 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3197 if (!(ffu_map & 1)) continue;
3199 if (This->texUnitMap[i] != tex) {
3200 device_map_stage(This, i, tex);
3201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3202 markTextureStagesDirty(This, i);
3205 ++tex;
3209 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3211 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3212 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3213 unsigned int i;
3215 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3216 if (sampler_type[i] && This->texUnitMap[i] != i)
3218 device_map_stage(This, i, i);
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3220 if (i < gl_info->limits.texture_stages)
3222 markTextureStagesDirty(This, i);
3228 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3229 const DWORD *vshader_sampler_tokens, DWORD unit)
3231 DWORD current_mapping = This->rev_tex_unit_map[unit];
3233 /* Not currently used */
3234 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3236 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3237 /* Used by a fragment sampler */
3239 if (!pshader_sampler_tokens) {
3240 /* No pixel shader, check fixed function */
3241 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3244 /* Pixel shader, check the shader's sampler map */
3245 return !pshader_sampler_tokens[current_mapping];
3248 /* Used by a vertex sampler */
3249 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3252 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3254 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3255 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3256 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3257 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3258 int i;
3260 if (ps) {
3261 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3263 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3264 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3265 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3268 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3269 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3270 if (vshader_sampler_type[i])
3272 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3274 /* Already mapped somewhere */
3275 continue;
3278 while (start >= 0) {
3279 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3281 device_map_stage(This, vsampler_idx, start);
3282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3284 --start;
3285 break;
3288 --start;
3294 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3296 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3297 BOOL vs = use_vs(This->stateBlock);
3298 BOOL ps = use_ps(This->stateBlock);
3300 * Rules are:
3301 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3302 * that would be really messy and require shader recompilation
3303 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3304 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3306 if (ps) device_map_psamplers(This, gl_info);
3307 else device_map_fixed_function_samplers(This, gl_info);
3309 if (vs) device_map_vsamplers(This, ps, gl_info);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3314 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3315 This->updateStateBlock->pixelShader = pShader;
3316 This->updateStateBlock->changed.pixelShader = TRUE;
3318 /* Handle recording of state blocks */
3319 if (This->isRecordingState) {
3320 TRACE("Recording... not performing anything\n");
3323 if (This->isRecordingState) {
3324 TRACE("Recording... not performing anything\n");
3325 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3326 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3327 return WINED3D_OK;
3330 if(pShader == oldShader) {
3331 TRACE("App is setting the old pixel shader over, nothing to do\n");
3332 return WINED3D_OK;
3335 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3336 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3338 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3341 return WINED3D_OK;
3344 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 if (NULL == ppShader) {
3348 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3349 return WINED3DERR_INVALIDCALL;
3352 *ppShader = This->stateBlock->pixelShader;
3353 if (NULL != *ppShader) {
3354 IWineD3DPixelShader_AddRef(*ppShader);
3356 TRACE("(%p) : returning %p\n", This, *ppShader);
3357 return WINED3D_OK;
3360 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3361 IWineD3DDevice *iface,
3362 UINT start,
3363 CONST BOOL *srcData,
3364 UINT count) {
3366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3367 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3369 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3370 iface, srcData, start, count);
3372 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3374 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3375 for (i = 0; i < cnt; i++)
3376 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3378 for (i = start; i < cnt + start; ++i) {
3379 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3382 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3384 return WINED3D_OK;
3387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3388 IWineD3DDevice *iface,
3389 UINT start,
3390 BOOL *dstData,
3391 UINT count) {
3393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 int cnt = min(count, MAX_CONST_B - start);
3396 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3397 iface, dstData, start, count);
3399 if (dstData == NULL || cnt < 0)
3400 return WINED3DERR_INVALIDCALL;
3402 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3403 return WINED3D_OK;
3406 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3407 IWineD3DDevice *iface,
3408 UINT start,
3409 CONST int *srcData,
3410 UINT count) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3413 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3415 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3416 iface, srcData, start, count);
3418 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3420 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3421 for (i = 0; i < cnt; i++)
3422 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3423 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3425 for (i = start; i < cnt + start; ++i) {
3426 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3429 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3431 return WINED3D_OK;
3434 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3435 IWineD3DDevice *iface,
3436 UINT start,
3437 int *dstData,
3438 UINT count) {
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 int cnt = min(count, MAX_CONST_I - start);
3443 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3444 iface, dstData, start, count);
3446 if (dstData == NULL || cnt < 0)
3447 return WINED3DERR_INVALIDCALL;
3449 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3450 return WINED3D_OK;
3453 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3454 IWineD3DDevice *iface,
3455 UINT start,
3456 CONST float *srcData,
3457 UINT count) {
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3460 UINT i;
3462 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3463 iface, srcData, start, count);
3465 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3466 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3467 return WINED3DERR_INVALIDCALL;
3469 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3470 if(TRACE_ON(d3d)) {
3471 for (i = 0; i < count; i++)
3472 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3473 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3476 if (!This->isRecordingState)
3478 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3482 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3483 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3485 return WINED3D_OK;
3488 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3489 IWineD3DDevice *iface,
3490 UINT start,
3491 float *dstData,
3492 UINT count) {
3494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3495 int cnt = min(count, This->d3d_pshader_constantF - start);
3497 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3498 iface, dstData, start, count);
3500 if (dstData == NULL || cnt < 0)
3501 return WINED3DERR_INVALIDCALL;
3503 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3504 return WINED3D_OK;
3507 /* Context activation is done by the caller. */
3508 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3509 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3510 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3511 DWORD DestFVF)
3513 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3514 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3515 unsigned int i;
3516 WINED3DVIEWPORT vp;
3517 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3518 BOOL doClip;
3519 DWORD numTextures;
3521 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3523 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3526 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3528 ERR("Source has no position mask\n");
3529 return WINED3DERR_INVALIDCALL;
3532 /* We might access VBOs from this code, so hold the lock */
3533 ENTER_GL();
3535 if (dest->resource.allocatedMemory == NULL) {
3536 buffer_get_sysmem(dest);
3539 /* Get a pointer into the destination vbo(create one if none exists) and
3540 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3542 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3544 dest->flags |= WINED3D_BUFFER_CREATEBO;
3545 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3548 if (dest->buffer_object)
3550 unsigned char extrabytes = 0;
3551 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3552 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3553 * this may write 4 extra bytes beyond the area that should be written
3555 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3556 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3557 if(!dest_conv_addr) {
3558 ERR("Out of memory\n");
3559 /* Continue without storing converted vertices */
3561 dest_conv = dest_conv_addr;
3564 /* Should I clip?
3565 * a) WINED3DRS_CLIPPING is enabled
3566 * b) WINED3DVOP_CLIP is passed
3568 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3569 static BOOL warned = FALSE;
3571 * The clipping code is not quite correct. Some things need
3572 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3573 * so disable clipping for now.
3574 * (The graphics in Half-Life are broken, and my processvertices
3575 * test crashes with IDirect3DDevice3)
3576 doClip = TRUE;
3578 doClip = FALSE;
3579 if(!warned) {
3580 warned = TRUE;
3581 FIXME("Clipping is broken and disabled for now\n");
3583 } else doClip = FALSE;
3584 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3586 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3587 WINED3DTS_VIEW,
3588 &view_mat);
3589 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3590 WINED3DTS_PROJECTION,
3591 &proj_mat);
3592 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3593 WINED3DTS_WORLDMATRIX(0),
3594 &world_mat);
3596 TRACE("View mat:\n");
3597 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);
3598 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);
3599 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);
3600 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);
3602 TRACE("Proj mat:\n");
3603 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);
3604 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);
3605 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);
3606 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);
3608 TRACE("World mat:\n");
3609 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);
3610 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);
3611 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);
3612 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);
3614 /* Get the viewport */
3615 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3616 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3617 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3619 multiply_matrix(&mat,&view_mat,&world_mat);
3620 multiply_matrix(&mat,&proj_mat,&mat);
3622 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3624 for (i = 0; i < dwCount; i+= 1) {
3625 unsigned int tex_index;
3627 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3628 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3629 /* The position first */
3630 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3631 const float *p = (const float *)(element->data + i * element->stride);
3632 float x, y, z, rhw;
3633 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3635 /* Multiplication with world, view and projection matrix */
3636 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);
3637 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);
3638 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);
3639 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);
3641 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3643 /* WARNING: The following things are taken from d3d7 and were not yet checked
3644 * against d3d8 or d3d9!
3647 /* Clipping conditions: From msdn
3649 * A vertex is clipped if it does not match the following requirements
3650 * -rhw < x <= rhw
3651 * -rhw < y <= rhw
3652 * 0 < z <= rhw
3653 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3655 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3656 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3660 if( !doClip ||
3661 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3662 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3663 ( rhw > eps ) ) ) {
3665 /* "Normal" viewport transformation (not clipped)
3666 * 1) The values are divided by rhw
3667 * 2) The y axis is negative, so multiply it with -1
3668 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3669 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3670 * 4) Multiply x with Width/2 and add Width/2
3671 * 5) The same for the height
3672 * 6) Add the viewpoint X and Y to the 2D coordinates and
3673 * The minimum Z value to z
3674 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3676 * Well, basically it's simply a linear transformation into viewport
3677 * coordinates
3680 x /= rhw;
3681 y /= rhw;
3682 z /= rhw;
3684 y *= -1;
3686 x *= vp.Width / 2;
3687 y *= vp.Height / 2;
3688 z *= vp.MaxZ - vp.MinZ;
3690 x += vp.Width / 2 + vp.X;
3691 y += vp.Height / 2 + vp.Y;
3692 z += vp.MinZ;
3694 rhw = 1 / rhw;
3695 } else {
3696 /* That vertex got clipped
3697 * Contrary to OpenGL it is not dropped completely, it just
3698 * undergoes a different calculation.
3700 TRACE("Vertex got clipped\n");
3701 x += rhw;
3702 y += rhw;
3704 x /= 2;
3705 y /= 2;
3707 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3708 * outside of the main vertex buffer memory. That needs some more
3709 * investigation...
3713 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3716 ( (float *) dest_ptr)[0] = x;
3717 ( (float *) dest_ptr)[1] = y;
3718 ( (float *) dest_ptr)[2] = z;
3719 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3721 dest_ptr += 3 * sizeof(float);
3723 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3724 dest_ptr += sizeof(float);
3727 if(dest_conv) {
3728 float w = 1 / rhw;
3729 ( (float *) dest_conv)[0] = x * w;
3730 ( (float *) dest_conv)[1] = y * w;
3731 ( (float *) dest_conv)[2] = z * w;
3732 ( (float *) dest_conv)[3] = w;
3734 dest_conv += 3 * sizeof(float);
3736 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3737 dest_conv += sizeof(float);
3741 if (DestFVF & WINED3DFVF_PSIZE) {
3742 dest_ptr += sizeof(DWORD);
3743 if(dest_conv) dest_conv += sizeof(DWORD);
3745 if (DestFVF & WINED3DFVF_NORMAL) {
3746 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3747 const float *normal = (const float *)(element->data + i * element->stride);
3748 /* AFAIK this should go into the lighting information */
3749 FIXME("Didn't expect the destination to have a normal\n");
3750 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3751 if(dest_conv) {
3752 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3756 if (DestFVF & WINED3DFVF_DIFFUSE) {
3757 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3758 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3759 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3761 static BOOL warned = FALSE;
3763 if(!warned) {
3764 ERR("No diffuse color in source, but destination has one\n");
3765 warned = TRUE;
3768 *( (DWORD *) dest_ptr) = 0xffffffff;
3769 dest_ptr += sizeof(DWORD);
3771 if(dest_conv) {
3772 *( (DWORD *) dest_conv) = 0xffffffff;
3773 dest_conv += sizeof(DWORD);
3776 else {
3777 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3778 if(dest_conv) {
3779 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3780 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3781 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3782 dest_conv += sizeof(DWORD);
3787 if (DestFVF & WINED3DFVF_SPECULAR)
3789 /* What's the color value in the feedback buffer? */
3790 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3791 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3792 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3794 static BOOL warned = FALSE;
3796 if(!warned) {
3797 ERR("No specular color in source, but destination has one\n");
3798 warned = TRUE;
3801 *( (DWORD *) dest_ptr) = 0xFF000000;
3802 dest_ptr += sizeof(DWORD);
3804 if(dest_conv) {
3805 *( (DWORD *) dest_conv) = 0xFF000000;
3806 dest_conv += sizeof(DWORD);
3809 else {
3810 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3811 if(dest_conv) {
3812 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3813 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3814 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3815 dest_conv += sizeof(DWORD);
3820 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3821 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3822 const float *tex_coord = (const float *)(element->data + i * element->stride);
3823 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3825 ERR("No source texture, but destination requests one\n");
3826 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3827 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3829 else {
3830 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3831 if(dest_conv) {
3832 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3838 if(dest_conv) {
3839 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3840 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3841 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3842 dwCount * get_flexible_vertex_size(DestFVF),
3843 dest_conv_addr));
3844 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3845 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3848 LEAVE_GL();
3850 return WINED3D_OK;
3852 #undef copy_and_next
3854 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3855 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3856 DWORD DestFVF)
3858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3859 struct wined3d_stream_info stream_info;
3860 struct wined3d_context *context;
3861 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3862 HRESULT hr;
3864 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3866 if(pVertexDecl) {
3867 ERR("Output vertex declaration not implemented yet\n");
3870 /* Need any context to write to the vbo. */
3871 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3873 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3874 * control the streamIsUP flag, thus restore it afterwards.
3876 This->stateBlock->streamIsUP = FALSE;
3877 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3878 This->stateBlock->streamIsUP = streamWasUP;
3880 if(vbo || SrcStartIndex) {
3881 unsigned int i;
3882 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3883 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3885 * Also get the start index in, but only loop over all elements if there's something to add at all.
3887 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3889 struct wined3d_stream_info_element *e;
3891 if (!(stream_info.use_map & (1 << i))) continue;
3893 e = &stream_info.elements[i];
3894 if (e->buffer_object)
3896 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3897 e->buffer_object = 0;
3898 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3899 ENTER_GL();
3900 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3901 vb->buffer_object = 0;
3902 LEAVE_GL();
3904 if (e->data) e->data += e->stride * SrcStartIndex;
3908 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3909 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3911 context_release(context);
3913 return hr;
3916 /*****
3917 * Get / Set Texture Stage States
3918 * TODO: Verify against dx9 definitions
3919 *****/
3920 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3922 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3923 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3925 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3927 if (Stage >= gl_info->limits.texture_stages)
3929 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3930 Stage, gl_info->limits.texture_stages - 1);
3931 return WINED3D_OK;
3934 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3935 This->updateStateBlock->textureState[Stage][Type] = Value;
3937 if (This->isRecordingState) {
3938 TRACE("Recording... not performing anything\n");
3939 return WINED3D_OK;
3942 /* Checked after the assignments to allow proper stateblock recording */
3943 if(oldValue == Value) {
3944 TRACE("App is setting the old value over, nothing to do\n");
3945 return WINED3D_OK;
3948 if(Stage > This->stateBlock->lowest_disabled_stage &&
3949 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3950 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3951 * Changes in other states are important on disabled stages too
3953 return WINED3D_OK;
3956 if(Type == WINED3DTSS_COLOROP) {
3957 unsigned int i;
3959 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3960 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3961 * they have to be disabled
3963 * The current stage is dirtified below.
3965 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3966 TRACE("Additionally dirtifying stage %u\n", i);
3967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3969 This->stateBlock->lowest_disabled_stage = Stage;
3970 TRACE("New lowest disabled: %u\n", Stage);
3971 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3972 /* Previously disabled stage enabled. Stages above it may need enabling
3973 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3974 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3976 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3979 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3981 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3982 break;
3984 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3985 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3987 This->stateBlock->lowest_disabled_stage = i;
3988 TRACE("New lowest disabled: %u\n", i);
3992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3994 return WINED3D_OK;
3997 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3999 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4000 *pValue = This->updateStateBlock->textureState[Stage][Type];
4001 return WINED3D_OK;
4004 /*****
4005 * Get / Set Texture
4006 *****/
4007 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4008 DWORD stage, IWineD3DBaseTexture *texture)
4010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4011 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4012 IWineD3DBaseTexture *prev;
4014 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4016 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4017 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4019 /* Windows accepts overflowing this array... we do not. */
4020 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4022 WARN("Ignoring invalid stage %u.\n", stage);
4023 return WINED3D_OK;
4026 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4027 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4029 WARN("Rejecting attempt to set scratch texture.\n");
4030 return WINED3DERR_INVALIDCALL;
4033 This->updateStateBlock->changed.textures |= 1 << stage;
4035 prev = This->updateStateBlock->textures[stage];
4036 TRACE("Previous texture %p.\n", prev);
4038 if (texture == prev)
4040 TRACE("App is setting the same texture again, nothing to do.\n");
4041 return WINED3D_OK;
4044 TRACE("Setting new texture to %p.\n", texture);
4045 This->updateStateBlock->textures[stage] = texture;
4047 if (This->isRecordingState)
4049 TRACE("Recording... not performing anything\n");
4051 if (texture) IWineD3DBaseTexture_AddRef(texture);
4052 if (prev) IWineD3DBaseTexture_Release(prev);
4054 return WINED3D_OK;
4057 if (texture)
4059 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4060 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4061 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4063 IWineD3DBaseTexture_AddRef(texture);
4065 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4070 if (!prev && stage < gl_info->limits.texture_stages)
4072 /* The source arguments for color and alpha ops have different
4073 * meanings when a NULL texture is bound, so the COLOROP and
4074 * ALPHAOP have to be dirtified. */
4075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4079 if (bind_count == 1) t->baseTexture.sampler = stage;
4082 if (prev)
4084 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4085 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4087 IWineD3DBaseTexture_Release(prev);
4089 if (!texture && stage < gl_info->limits.texture_stages)
4091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4095 if (bind_count && t->baseTexture.sampler == stage)
4097 unsigned int i;
4099 /* Search for other stages the texture is bound to. Shouldn't
4100 * happen if applications bind textures to a single stage only. */
4101 TRACE("Searching for other stages the texture is bound to.\n");
4102 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4104 if (This->updateStateBlock->textures[i] == prev)
4106 TRACE("Texture is also bound to stage %u.\n", i);
4107 t->baseTexture.sampler = i;
4108 break;
4114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4116 return WINED3D_OK;
4119 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4122 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4124 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4125 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4128 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4129 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4130 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4133 *ppTexture=This->stateBlock->textures[Stage];
4134 if (*ppTexture)
4135 IWineD3DBaseTexture_AddRef(*ppTexture);
4137 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4139 return WINED3D_OK;
4142 /*****
4143 * Get Back Buffer
4144 *****/
4145 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4146 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4148 IWineD3DSwapChain *swapchain;
4149 HRESULT hr;
4151 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4152 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4154 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4155 if (FAILED(hr))
4157 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4158 return hr;
4161 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4162 IWineD3DSwapChain_Release(swapchain);
4163 if (FAILED(hr))
4165 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4166 return hr;
4169 return WINED3D_OK;
4172 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4174 WARN("(%p) : stub, calling idirect3d for now\n", This);
4175 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4178 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4180 IWineD3DSwapChain *swapChain;
4181 HRESULT hr;
4183 if(iSwapChain > 0) {
4184 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4185 if (hr == WINED3D_OK) {
4186 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4187 IWineD3DSwapChain_Release(swapChain);
4188 } else {
4189 FIXME("(%p) Error getting display mode\n", This);
4191 } else {
4192 /* Don't read the real display mode,
4193 but return the stored mode instead. X11 can't change the color
4194 depth, and some apps are pretty angry if they SetDisplayMode from
4195 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4197 Also don't relay to the swapchain because with ddraw it's possible
4198 that there isn't a swapchain at all */
4199 pMode->Width = This->ddraw_width;
4200 pMode->Height = This->ddraw_height;
4201 pMode->Format = This->ddraw_format;
4202 pMode->RefreshRate = 0;
4203 hr = WINED3D_OK;
4206 return hr;
4209 /*****
4210 * Stateblock related functions
4211 *****/
4213 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4215 IWineD3DStateBlock *stateblock;
4216 HRESULT hr;
4218 TRACE("(%p)\n", This);
4220 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4222 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4223 if (FAILED(hr)) return hr;
4225 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4226 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4227 This->isRecordingState = TRUE;
4229 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4231 return WINED3D_OK;
4234 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4238 if (!This->isRecordingState) {
4239 WARN("(%p) not recording! returning error\n", This);
4240 *ppStateBlock = NULL;
4241 return WINED3DERR_INVALIDCALL;
4244 stateblock_init_contained_states(object);
4246 *ppStateBlock = (IWineD3DStateBlock*) object;
4247 This->isRecordingState = FALSE;
4248 This->updateStateBlock = This->stateBlock;
4249 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4250 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4251 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4252 return WINED3D_OK;
4255 /*****
4256 * Scene related functions
4257 *****/
4258 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4259 /* At the moment we have no need for any functionality at the beginning
4260 of a scene */
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 TRACE("(%p)\n", This);
4264 if(This->inScene) {
4265 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4266 return WINED3DERR_INVALIDCALL;
4268 This->inScene = TRUE;
4269 return WINED3D_OK;
4272 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4275 struct wined3d_context *context;
4277 TRACE("(%p)\n", This);
4279 if(!This->inScene) {
4280 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4281 return WINED3DERR_INVALIDCALL;
4284 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4285 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4286 wglFlush();
4287 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4288 * fails. */
4289 context_release(context);
4291 This->inScene = FALSE;
4292 return WINED3D_OK;
4295 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4296 const RECT *pSourceRect, const RECT *pDestRect,
4297 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4299 IWineD3DSwapChain *swapChain = NULL;
4300 int i;
4301 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4303 TRACE("iface %p.\n", iface);
4305 for(i = 0 ; i < swapchains ; i ++) {
4307 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4308 TRACE("presentinng chain %d, %p\n", i, swapChain);
4309 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4310 IWineD3DSwapChain_Release(swapChain);
4313 return WINED3D_OK;
4316 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4317 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4319 /* partial viewport*/
4320 if (viewport->X != 0 || viewport->Y != 0
4321 || viewport->Width < target->currentDesc.Width
4322 || viewport->Height < target->currentDesc.Height)
4323 return FALSE;
4325 /* partial scissor rect */
4326 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4327 || scissor_rect->right < target->currentDesc.Width
4328 || scissor_rect->bottom < target->currentDesc.Height))
4329 return FALSE;
4331 /* partial clear rect */
4332 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4333 || clear_rect->x2 < target->currentDesc.Width
4334 || clear_rect->y2 < target->currentDesc.Height))
4335 return FALSE;
4337 return TRUE;
4340 /* Not called from the VTable (internal subroutine) */
4341 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4342 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4344 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4345 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4346 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4347 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4348 GLbitfield glMask = 0;
4349 unsigned int i;
4350 WINED3DRECT curRect;
4351 RECT vp_rect;
4352 UINT drawable_width, drawable_height;
4353 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4354 struct wined3d_context *context;
4356 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4357 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4358 * for the cleared parts, and the untouched parts.
4360 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4361 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4362 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4363 * checking all this if the dest surface is in the drawable anyway.
4365 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4367 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4368 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4371 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4372 if (!context->valid)
4374 context_release(context);
4375 WARN("Invalid context, skipping clear.\n");
4376 return WINED3D_OK;
4379 target->get_drawable_size(context, &drawable_width, &drawable_height);
4381 ENTER_GL();
4383 /* Only set the values up once, as they are not changing */
4384 if (Flags & WINED3DCLEAR_STENCIL) {
4385 glClearStencil(Stencil);
4386 checkGLcall("glClearStencil");
4387 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4388 glStencilMask(0xFFFFFFFF);
4391 if (Flags & WINED3DCLEAR_ZBUFFER) {
4392 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4393 glDepthMask(GL_TRUE);
4394 glClearDepth(Z);
4395 checkGLcall("glClearDepth");
4396 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4399 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4400 surface_load_ds_location(This->stencilBufferTarget, context, location);
4403 if (Flags & WINED3DCLEAR_TARGET) {
4404 TRACE("Clearing screen with glClear to color %x\n", Color);
4405 glClearColor(D3DCOLOR_R(Color),
4406 D3DCOLOR_G(Color),
4407 D3DCOLOR_B(Color),
4408 D3DCOLOR_A(Color));
4409 checkGLcall("glClearColor");
4411 /* Clear ALL colors! */
4412 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4413 glMask = glMask | GL_COLOR_BUFFER_BIT;
4416 vp_rect.left = vp->X;
4417 vp_rect.top = vp->Y;
4418 vp_rect.right = vp->X + vp->Width;
4419 vp_rect.bottom = vp->Y + vp->Height;
4420 if (!(Count > 0 && pRects)) {
4421 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4422 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4424 if (context->render_offscreen)
4426 glScissor(vp_rect.left, vp_rect.top,
4427 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4428 } else {
4429 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4430 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4432 checkGLcall("glScissor");
4433 glClear(glMask);
4434 checkGLcall("glClear");
4435 } else {
4436 /* Now process each rect in turn */
4437 for (i = 0; i < Count; i++) {
4438 /* Note gl uses lower left, width/height */
4439 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4440 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4441 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4443 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4444 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4445 curRect.x1, (target->currentDesc.Height - curRect.y2),
4446 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4448 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4449 * The rectangle is not cleared, no error is returned, but further rectanlges are
4450 * still cleared if they are valid
4452 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4453 TRACE("Rectangle with negative dimensions, ignoring\n");
4454 continue;
4457 if (context->render_offscreen)
4459 glScissor(curRect.x1, curRect.y1,
4460 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4461 } else {
4462 glScissor(curRect.x1, drawable_height - curRect.y2,
4463 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4465 checkGLcall("glScissor");
4467 glClear(glMask);
4468 checkGLcall("glClear");
4472 /* Restore the old values (why..?) */
4473 if (Flags & WINED3DCLEAR_STENCIL) {
4474 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4476 if (Flags & WINED3DCLEAR_TARGET) {
4477 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4478 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4479 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4480 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4481 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4483 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4484 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4486 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4488 if (Flags & WINED3DCLEAR_ZBUFFER) {
4489 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4490 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4491 surface_modify_ds_location(This->stencilBufferTarget, location);
4494 LEAVE_GL();
4496 wglFlush(); /* Flush to ensure ordering across contexts. */
4498 context_release(context);
4500 return WINED3D_OK;
4503 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4504 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4508 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4509 Count, pRects, Flags, Color, Z, Stencil);
4511 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4512 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4513 /* TODO: What about depth stencil buffers without stencil bits? */
4514 return WINED3DERR_INVALIDCALL;
4517 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4520 /*****
4521 * Drawing functions
4522 *****/
4524 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4525 WINED3DPRIMITIVETYPE primitive_type)
4527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4531 This->updateStateBlock->changed.primitive_type = TRUE;
4532 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4535 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4536 WINED3DPRIMITIVETYPE *primitive_type)
4538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4540 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4542 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4544 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4547 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4553 if(!This->stateBlock->vertexDecl) {
4554 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4555 return WINED3DERR_INVALIDCALL;
4558 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4559 if(This->stateBlock->streamIsUP) {
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4561 This->stateBlock->streamIsUP = FALSE;
4564 if(This->stateBlock->loadBaseVertexIndex != 0) {
4565 This->stateBlock->loadBaseVertexIndex = 0;
4566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4568 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4569 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4570 return WINED3D_OK;
4573 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 UINT idxStride = 2;
4577 IWineD3DBuffer *pIB;
4578 GLuint vbo;
4580 pIB = This->stateBlock->pIndexData;
4581 if (!pIB) {
4582 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4583 * without an index buffer set. (The first time at least...)
4584 * D3D8 simply dies, but I doubt it can do much harm to return
4585 * D3DERR_INVALIDCALL there as well. */
4586 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4587 return WINED3DERR_INVALIDCALL;
4590 if(!This->stateBlock->vertexDecl) {
4591 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4592 return WINED3DERR_INVALIDCALL;
4595 if(This->stateBlock->streamIsUP) {
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4597 This->stateBlock->streamIsUP = FALSE;
4599 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4601 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4603 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4604 idxStride = 2;
4605 } else {
4606 idxStride = 4;
4609 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4610 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4614 drawPrimitive(iface, index_count, startIndex, idxStride,
4615 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4617 return WINED3D_OK;
4620 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4621 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 IWineD3DBuffer *vb;
4626 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4627 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4629 if(!This->stateBlock->vertexDecl) {
4630 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4631 return WINED3DERR_INVALIDCALL;
4634 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4635 vb = This->stateBlock->streamSource[0];
4636 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4637 if (vb) IWineD3DBuffer_Release(vb);
4638 This->stateBlock->streamOffset[0] = 0;
4639 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4640 This->stateBlock->streamIsUP = TRUE;
4641 This->stateBlock->loadBaseVertexIndex = 0;
4643 /* TODO: Only mark dirty if drawing from a different UP address */
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4646 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4648 /* MSDN specifies stream zero settings must be set to NULL */
4649 This->stateBlock->streamStride[0] = 0;
4650 This->stateBlock->streamSource[0] = NULL;
4652 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4653 * the new stream sources or use UP drawing again
4655 return WINED3D_OK;
4658 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4659 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4660 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4662 int idxStride;
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 IWineD3DBuffer *vb;
4665 IWineD3DBuffer *ib;
4667 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4668 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4670 if(!This->stateBlock->vertexDecl) {
4671 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4672 return WINED3DERR_INVALIDCALL;
4675 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4676 idxStride = 2;
4677 } else {
4678 idxStride = 4;
4681 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4682 vb = This->stateBlock->streamSource[0];
4683 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4684 if (vb) IWineD3DBuffer_Release(vb);
4685 This->stateBlock->streamIsUP = TRUE;
4686 This->stateBlock->streamOffset[0] = 0;
4687 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4689 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4690 This->stateBlock->baseVertexIndex = 0;
4691 This->stateBlock->loadBaseVertexIndex = 0;
4692 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4696 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4698 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4699 This->stateBlock->streamSource[0] = NULL;
4700 This->stateBlock->streamStride[0] = 0;
4701 ib = This->stateBlock->pIndexData;
4702 if(ib) {
4703 IWineD3DBuffer_Release(ib);
4704 This->stateBlock->pIndexData = NULL;
4706 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4707 * SetStreamSource to specify a vertex buffer
4710 return WINED3D_OK;
4713 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4714 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4718 /* Mark the state dirty until we have nicer tracking
4719 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4720 * that value.
4722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4724 This->stateBlock->baseVertexIndex = 0;
4725 This->up_strided = DrawPrimStrideData;
4726 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4727 This->up_strided = NULL;
4728 return WINED3D_OK;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4732 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4733 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4736 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4738 /* Mark the state dirty until we have nicer tracking
4739 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4740 * that value.
4742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4744 This->stateBlock->streamIsUP = TRUE;
4745 This->stateBlock->baseVertexIndex = 0;
4746 This->up_strided = DrawPrimStrideData;
4747 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4748 This->up_strided = NULL;
4749 return WINED3D_OK;
4752 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4753 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4754 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4756 WINED3DLOCKED_BOX src;
4757 WINED3DLOCKED_BOX dst;
4758 HRESULT hr;
4760 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4761 iface, pSourceVolume, pDestinationVolume);
4763 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4764 * dirtification to improve loading performance.
4766 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4767 if(FAILED(hr)) return hr;
4768 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4769 if(FAILED(hr)) {
4770 IWineD3DVolume_UnlockBox(pSourceVolume);
4771 return hr;
4774 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4776 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4777 if(FAILED(hr)) {
4778 IWineD3DVolume_UnlockBox(pSourceVolume);
4779 } else {
4780 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4782 return hr;
4785 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4786 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4788 unsigned int level_count, i;
4789 WINED3DRESOURCETYPE type;
4790 HRESULT hr;
4792 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4794 /* Verify that the source and destination textures are non-NULL. */
4795 if (!src_texture || !dst_texture)
4797 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4798 return WINED3DERR_INVALIDCALL;
4801 if (src_texture == dst_texture)
4803 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4804 return WINED3DERR_INVALIDCALL;
4807 /* Verify that the source and destination textures are the same type. */
4808 type = IWineD3DBaseTexture_GetType(src_texture);
4809 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4811 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4812 return WINED3DERR_INVALIDCALL;
4815 /* Check that both textures have the identical numbers of levels. */
4816 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4817 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4819 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4820 return WINED3DERR_INVALIDCALL;
4823 /* Make sure that the destination texture is loaded. */
4824 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4826 /* Update every surface level of the texture. */
4827 switch (type)
4829 case WINED3DRTYPE_TEXTURE:
4831 IWineD3DSurface *src_surface;
4832 IWineD3DSurface *dst_surface;
4834 for (i = 0; i < level_count; ++i)
4836 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4837 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4838 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4839 IWineD3DSurface_Release(dst_surface);
4840 IWineD3DSurface_Release(src_surface);
4841 if (FAILED(hr))
4843 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4844 return hr;
4847 break;
4850 case WINED3DRTYPE_CUBETEXTURE:
4852 IWineD3DSurface *src_surface;
4853 IWineD3DSurface *dst_surface;
4854 WINED3DCUBEMAP_FACES face;
4856 for (i = 0; i < level_count; ++i)
4858 /* Update each cube face. */
4859 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4861 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4862 face, i, &src_surface);
4863 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4864 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4865 face, i, &dst_surface);
4866 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4867 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4868 IWineD3DSurface_Release(dst_surface);
4869 IWineD3DSurface_Release(src_surface);
4870 if (FAILED(hr))
4872 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4873 return hr;
4877 break;
4880 case WINED3DRTYPE_VOLUMETEXTURE:
4882 IWineD3DVolume *src_volume;
4883 IWineD3DVolume *dst_volume;
4885 for (i = 0; i < level_count; ++i)
4887 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4888 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4889 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4890 IWineD3DVolume_Release(dst_volume);
4891 IWineD3DVolume_Release(src_volume);
4892 if (FAILED(hr))
4894 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4895 return hr;
4898 break;
4901 default:
4902 FIXME("Unsupported texture type %#x.\n", type);
4903 return WINED3DERR_INVALIDCALL;
4906 return WINED3D_OK;
4909 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4910 IWineD3DSwapChain *swapChain;
4911 HRESULT hr;
4912 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4913 if(hr == WINED3D_OK) {
4914 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4915 IWineD3DSwapChain_Release(swapChain);
4917 return hr;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4922 IWineD3DBaseTextureImpl *texture;
4923 DWORD i;
4925 TRACE("(%p) : %p\n", This, pNumPasses);
4927 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4928 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4929 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4930 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4932 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4933 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4934 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4937 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4938 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4940 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4941 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4942 return E_FAIL;
4944 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4945 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4946 return E_FAIL;
4948 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4949 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4950 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4951 return E_FAIL;
4955 /* return a sensible default */
4956 *pNumPasses = 1;
4958 TRACE("returning D3D_OK\n");
4959 return WINED3D_OK;
4962 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4964 int i;
4966 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4968 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4969 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4970 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4972 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4977 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4979 int j;
4980 UINT NewSize;
4981 PALETTEENTRY **palettes;
4983 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4985 if (PaletteNumber >= MAX_PALETTES) {
4986 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4987 return WINED3DERR_INVALIDCALL;
4990 if (PaletteNumber >= This->NumberOfPalettes) {
4991 NewSize = This->NumberOfPalettes;
4992 do {
4993 NewSize *= 2;
4994 } while(PaletteNumber >= NewSize);
4995 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4996 if (!palettes) {
4997 ERR("Out of memory!\n");
4998 return E_OUTOFMEMORY;
5000 This->palettes = palettes;
5001 This->NumberOfPalettes = NewSize;
5004 if (!This->palettes[PaletteNumber]) {
5005 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5006 if (!This->palettes[PaletteNumber]) {
5007 ERR("Out of memory!\n");
5008 return E_OUTOFMEMORY;
5012 for (j = 0; j < 256; ++j) {
5013 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5014 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5015 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5016 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5018 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5019 TRACE("(%p) : returning\n", This);
5020 return WINED3D_OK;
5023 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5025 int j;
5026 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5027 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5028 /* What happens in such situation isn't documented; Native seems to silently abort
5029 on such conditions. Return Invalid Call. */
5030 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5031 return WINED3DERR_INVALIDCALL;
5033 for (j = 0; j < 256; ++j) {
5034 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5035 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5036 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5037 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5039 TRACE("(%p) : returning\n", This);
5040 return WINED3D_OK;
5043 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5045 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5046 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5047 (tested with reference rasterizer). Return Invalid Call. */
5048 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5049 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5050 return WINED3DERR_INVALIDCALL;
5052 /*TODO: stateblocks */
5053 if (This->currentPalette != PaletteNumber) {
5054 This->currentPalette = PaletteNumber;
5055 dirtify_p8_texture_samplers(This);
5057 TRACE("(%p) : returning\n", This);
5058 return WINED3D_OK;
5061 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 if (PaletteNumber == NULL) {
5064 WARN("(%p) : returning Invalid Call\n", This);
5065 return WINED3DERR_INVALIDCALL;
5067 /*TODO: stateblocks */
5068 *PaletteNumber = This->currentPalette;
5069 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5070 return WINED3D_OK;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5075 static BOOL warned;
5076 if (!warned)
5078 FIXME("(%p) : stub\n", This);
5079 warned = TRUE;
5082 This->softwareVertexProcessing = bSoftware;
5083 return WINED3D_OK;
5087 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 static BOOL warned;
5090 if (!warned)
5092 FIXME("(%p) : stub\n", This);
5093 warned = TRUE;
5095 return This->softwareVertexProcessing;
5098 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5099 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5101 IWineD3DSwapChain *swapchain;
5102 HRESULT hr;
5104 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5105 iface, swapchain_idx, raster_status);
5107 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5108 if (FAILED(hr))
5110 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5111 return hr;
5114 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5115 IWineD3DSwapChain_Release(swapchain);
5116 if (FAILED(hr))
5118 WARN("Failed to get raster status, hr %#x.\n", hr);
5119 return hr;
5122 return WINED3D_OK;
5125 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5127 static BOOL warned;
5128 if(nSegments != 0.0f) {
5129 if (!warned)
5131 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5132 warned = TRUE;
5135 return WINED3D_OK;
5138 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5140 static BOOL warned;
5141 if (!warned)
5143 FIXME("iface %p stub!\n", iface);
5144 warned = TRUE;
5146 return 0.0f;
5149 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5151 /** TODO: remove casts to IWineD3DSurfaceImpl
5152 * NOTE: move code to surface to accomplish this
5153 ****************************************/
5154 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5155 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5156 int srcWidth, srcHeight;
5157 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5158 WINED3DFORMAT destFormat, srcFormat;
5159 UINT destSize;
5160 int srcLeft, destLeft, destTop;
5161 WINED3DPOOL srcPool, destPool;
5162 int offset = 0;
5163 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5164 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5165 GLenum dummy;
5166 DWORD sampler;
5167 int bpp;
5168 CONVERT_TYPES convert = NO_CONVERSION;
5169 struct wined3d_context *context;
5171 WINED3DSURFACE_DESC winedesc;
5173 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5175 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5176 srcSurfaceWidth = winedesc.width;
5177 srcSurfaceHeight = winedesc.height;
5178 srcPool = winedesc.pool;
5179 srcFormat = winedesc.format;
5181 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5182 destSurfaceWidth = winedesc.width;
5183 destSurfaceHeight = winedesc.height;
5184 destPool = winedesc.pool;
5185 destFormat = winedesc.format;
5186 destSize = winedesc.size;
5188 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5189 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5190 return WINED3DERR_INVALIDCALL;
5193 /* This call loads the opengl surface directly, instead of copying the surface to the
5194 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5195 * copy in sysmem and use regular surface loading.
5197 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5198 if(convert != NO_CONVERSION) {
5199 return IWineD3DSurface_BltFast(pDestinationSurface,
5200 pDestPoint ? pDestPoint->x : 0,
5201 pDestPoint ? pDestPoint->y : 0,
5202 pSourceSurface, pSourceRect, 0);
5205 if (destFormat == WINED3DFMT_UNKNOWN) {
5206 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5207 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5209 /* Get the update surface description */
5210 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5213 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5215 ENTER_GL();
5216 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5217 checkGLcall("glActiveTextureARB");
5218 LEAVE_GL();
5220 /* Make sure the surface is loaded and up to date */
5221 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5222 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5224 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5225 dst_format_desc = dst_impl->resource.format_desc;
5227 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5228 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5229 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5230 srcLeft = pSourceRect ? pSourceRect->left : 0;
5231 destLeft = pDestPoint ? pDestPoint->x : 0;
5232 destTop = pDestPoint ? pDestPoint->y : 0;
5235 /* This function doesn't support compressed textures
5236 the pitch is just bytesPerPixel * width */
5237 if(srcWidth != srcSurfaceWidth || srcLeft ){
5238 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5239 offset += srcLeft * src_format_desc->byte_count;
5240 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5242 /* TODO DXT formats */
5244 if(pSourceRect != NULL && pSourceRect->top != 0){
5245 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5247 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5248 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5249 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5251 /* Sanity check */
5252 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5254 /* need to lock the surface to get the data */
5255 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5258 ENTER_GL();
5260 /* TODO: Cube and volume support */
5261 if(rowoffset != 0){
5262 /* not a whole row so we have to do it a line at a time */
5263 int j;
5265 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5266 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5268 for (j = destTop; j < (srcHeight + destTop); ++j)
5270 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5271 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5272 data += rowoffset;
5275 } else { /* Full width, so just write out the whole texture */
5276 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5278 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5280 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5282 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5283 FIXME("Updating part of a compressed texture is not supported.\n");
5285 if (destFormat != srcFormat)
5287 FIXME("Updating mixed format compressed textures is not supported.\n");
5289 else
5291 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5292 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5295 else
5297 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5298 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5301 checkGLcall("glTexSubImage2D");
5303 LEAVE_GL();
5304 context_release(context);
5306 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5307 sampler = This->rev_tex_unit_map[0];
5308 if (sampler != WINED3D_UNMAPPED_STAGE)
5310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5313 return WINED3D_OK;
5316 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5318 struct WineD3DRectPatch *patch;
5319 GLenum old_primitive_type;
5320 unsigned int i;
5321 struct list *e;
5322 BOOL found;
5323 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5325 if(!(Handle || pRectPatchInfo)) {
5326 /* TODO: Write a test for the return value, thus the FIXME */
5327 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5328 return WINED3DERR_INVALIDCALL;
5331 if(Handle) {
5332 i = PATCHMAP_HASHFUNC(Handle);
5333 found = FALSE;
5334 LIST_FOR_EACH(e, &This->patches[i]) {
5335 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5336 if(patch->Handle == Handle) {
5337 found = TRUE;
5338 break;
5342 if(!found) {
5343 TRACE("Patch does not exist. Creating a new one\n");
5344 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5345 patch->Handle = Handle;
5346 list_add_head(&This->patches[i], &patch->entry);
5347 } else {
5348 TRACE("Found existing patch %p\n", patch);
5350 } else {
5351 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5352 * attributes we have to tesselate, read back, and draw. This needs a patch
5353 * management structure instance. Create one.
5355 * A possible improvement is to check if a vertex shader is used, and if not directly
5356 * draw the patch.
5358 FIXME("Drawing an uncached patch. This is slow\n");
5359 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5362 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5363 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5364 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5365 HRESULT hr;
5366 TRACE("Tesselation density or patch info changed, retesselating\n");
5368 if(pRectPatchInfo) {
5369 patch->RectPatchInfo = *pRectPatchInfo;
5371 patch->numSegs[0] = pNumSegs[0];
5372 patch->numSegs[1] = pNumSegs[1];
5373 patch->numSegs[2] = pNumSegs[2];
5374 patch->numSegs[3] = pNumSegs[3];
5376 hr = tesselate_rectpatch(This, patch);
5377 if(FAILED(hr)) {
5378 WARN("Patch tesselation failed\n");
5380 /* Do not release the handle to store the params of the patch */
5381 if(!Handle) {
5382 HeapFree(GetProcessHeap(), 0, patch);
5384 return hr;
5388 This->currentPatch = patch;
5389 old_primitive_type = This->stateBlock->gl_primitive_type;
5390 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5391 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5392 This->stateBlock->gl_primitive_type = old_primitive_type;
5393 This->currentPatch = NULL;
5395 /* Destroy uncached patches */
5396 if(!Handle) {
5397 HeapFree(GetProcessHeap(), 0, patch->mem);
5398 HeapFree(GetProcessHeap(), 0, patch);
5400 return WINED3D_OK;
5403 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5404 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5406 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5407 iface, handle, segment_count, patch_info);
5409 return WINED3D_OK;
5412 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 int i;
5415 struct WineD3DRectPatch *patch;
5416 struct list *e;
5417 TRACE("(%p) Handle(%d)\n", This, Handle);
5419 i = PATCHMAP_HASHFUNC(Handle);
5420 LIST_FOR_EACH(e, &This->patches[i]) {
5421 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5422 if(patch->Handle == Handle) {
5423 TRACE("Deleting patch %p\n", patch);
5424 list_remove(&patch->entry);
5425 HeapFree(GetProcessHeap(), 0, patch->mem);
5426 HeapFree(GetProcessHeap(), 0, patch);
5427 return WINED3D_OK;
5431 /* TODO: Write a test for the return value */
5432 FIXME("Attempt to destroy nonexistent patch\n");
5433 return WINED3DERR_INVALIDCALL;
5436 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5437 const WINED3DRECT *rect, const float color[4])
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5440 struct wined3d_context *context;
5442 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5443 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5445 if (!surface_is_offscreen(surface))
5447 TRACE("Surface %p is onscreen\n", surface);
5449 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5450 ENTER_GL();
5451 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5452 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5454 else
5456 TRACE("Surface %p is offscreen\n", surface);
5458 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5459 ENTER_GL();
5460 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5461 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5462 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5465 if (rect) {
5466 glEnable(GL_SCISSOR_TEST);
5467 if(surface_is_offscreen(surface)) {
5468 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5469 } else {
5470 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5471 rect->x2 - rect->x1, rect->y2 - rect->y1);
5473 checkGLcall("glScissor");
5474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5475 } else {
5476 glDisable(GL_SCISSOR_TEST);
5478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5480 glDisable(GL_BLEND);
5481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5483 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5486 glClearColor(color[0], color[1], color[2], color[3]);
5487 glClear(GL_COLOR_BUFFER_BIT);
5488 checkGLcall("glClear");
5490 LEAVE_GL();
5492 wglFlush(); /* Flush to ensure ordering across contexts. */
5494 context_release(context);
5497 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5498 unsigned int r, g, b, a;
5499 DWORD ret;
5501 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5502 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5503 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5504 return color;
5506 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5508 a = (color & 0xff000000) >> 24;
5509 r = (color & 0x00ff0000) >> 16;
5510 g = (color & 0x0000ff00) >> 8;
5511 b = (color & 0x000000ff) >> 0;
5513 switch(destfmt)
5515 case WINED3DFMT_B5G6R5_UNORM:
5516 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5517 r = (r * 32) / 256;
5518 g = (g * 64) / 256;
5519 b = (b * 32) / 256;
5520 ret = r << 11;
5521 ret |= g << 5;
5522 ret |= b;
5523 TRACE("Returning %08x\n", ret);
5524 return ret;
5526 case WINED3DFMT_B5G5R5X1_UNORM:
5527 case WINED3DFMT_B5G5R5A1_UNORM:
5528 a = (a * 2) / 256;
5529 r = (r * 32) / 256;
5530 g = (g * 32) / 256;
5531 b = (b * 32) / 256;
5532 ret = a << 15;
5533 ret |= r << 10;
5534 ret |= g << 5;
5535 ret |= b << 0;
5536 TRACE("Returning %08x\n", ret);
5537 return ret;
5539 case WINED3DFMT_A8_UNORM:
5540 TRACE("Returning %08x\n", a);
5541 return a;
5543 case WINED3DFMT_B4G4R4X4_UNORM:
5544 case WINED3DFMT_B4G4R4A4_UNORM:
5545 a = (a * 16) / 256;
5546 r = (r * 16) / 256;
5547 g = (g * 16) / 256;
5548 b = (b * 16) / 256;
5549 ret = a << 12;
5550 ret |= r << 8;
5551 ret |= g << 4;
5552 ret |= b << 0;
5553 TRACE("Returning %08x\n", ret);
5554 return ret;
5556 case WINED3DFMT_B2G3R3_UNORM:
5557 r = (r * 8) / 256;
5558 g = (g * 8) / 256;
5559 b = (b * 4) / 256;
5560 ret = r << 5;
5561 ret |= g << 2;
5562 ret |= b << 0;
5563 TRACE("Returning %08x\n", ret);
5564 return ret;
5566 case WINED3DFMT_R8G8B8X8_UNORM:
5567 case WINED3DFMT_R8G8B8A8_UNORM:
5568 ret = a << 24;
5569 ret |= b << 16;
5570 ret |= g << 8;
5571 ret |= r << 0;
5572 TRACE("Returning %08x\n", ret);
5573 return ret;
5575 case WINED3DFMT_B10G10R10A2_UNORM:
5576 a = (a * 4) / 256;
5577 r = (r * 1024) / 256;
5578 g = (g * 1024) / 256;
5579 b = (b * 1024) / 256;
5580 ret = a << 30;
5581 ret |= r << 20;
5582 ret |= g << 10;
5583 ret |= b << 0;
5584 TRACE("Returning %08x\n", ret);
5585 return ret;
5587 case WINED3DFMT_R10G10B10A2_UNORM:
5588 a = (a * 4) / 256;
5589 r = (r * 1024) / 256;
5590 g = (g * 1024) / 256;
5591 b = (b * 1024) / 256;
5592 ret = a << 30;
5593 ret |= b << 20;
5594 ret |= g << 10;
5595 ret |= r << 0;
5596 TRACE("Returning %08x\n", ret);
5597 return ret;
5599 default:
5600 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5601 return 0;
5605 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5606 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5608 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5609 WINEDDBLTFX BltFx;
5611 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5613 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5614 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5615 return WINED3DERR_INVALIDCALL;
5618 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5619 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5620 color_fill_fbo(iface, pSurface, pRect, c);
5621 return WINED3D_OK;
5622 } else {
5623 /* Just forward this to the DirectDraw blitting engine */
5624 memset(&BltFx, 0, sizeof(BltFx));
5625 BltFx.dwSize = sizeof(BltFx);
5626 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5627 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5628 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5632 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5633 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5635 IWineD3DResource *resource;
5636 IWineD3DSurface *surface;
5637 HRESULT hr;
5639 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5640 if (FAILED(hr))
5642 ERR("Failed to get resource, hr %#x\n", hr);
5643 return;
5646 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5648 FIXME("Only supported on surface resources\n");
5649 IWineD3DResource_Release(resource);
5650 return;
5653 surface = (IWineD3DSurface *)resource;
5655 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5657 color_fill_fbo(iface, surface, NULL, color);
5659 else
5661 WINEDDBLTFX BltFx;
5662 WINED3DCOLOR c;
5664 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5666 c = ((DWORD)(color[2] * 255.0f));
5667 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5668 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5669 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5671 /* Just forward this to the DirectDraw blitting engine */
5672 memset(&BltFx, 0, sizeof(BltFx));
5673 BltFx.dwSize = sizeof(BltFx);
5674 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5675 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5676 if (FAILED(hr))
5678 ERR("Blt failed, hr %#x\n", hr);
5682 IWineD3DResource_Release(resource);
5685 /* rendertarget and depth stencil functions */
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5691 ERR("(%p) : Only %d render targets are supported.\n",
5692 This, This->adapter->gl_info.limits.buffers);
5693 return WINED3DERR_INVALIDCALL;
5696 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5697 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5698 /* Note inc ref on returned surface */
5699 if(*ppRenderTarget != NULL)
5700 IWineD3DSurface_AddRef(*ppRenderTarget);
5701 return WINED3D_OK;
5704 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5705 IWineD3DSurface *front, IWineD3DSurface *back)
5707 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5708 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5709 IWineD3DSwapChainImpl *swapchain;
5710 HRESULT hr;
5712 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5714 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5716 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5717 return hr;
5720 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5722 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5723 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5724 return WINED3DERR_INVALIDCALL;
5727 if (back_impl)
5729 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5731 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5732 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5733 return WINED3DERR_INVALIDCALL;
5736 if (!swapchain->backBuffer)
5738 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5739 if (!swapchain->backBuffer)
5741 ERR("Failed to allocate back buffer array memory.\n");
5742 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5743 return E_OUTOFMEMORY;
5748 if (swapchain->frontBuffer != front)
5750 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5752 if (swapchain->frontBuffer)
5754 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5755 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5757 swapchain->frontBuffer = front;
5759 if (front)
5761 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5762 front_impl->Flags |= SFLAG_SWAPCHAIN;
5766 if (swapchain->backBuffer[0] != back)
5768 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5770 if (swapchain->backBuffer[0])
5772 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5773 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5775 swapchain->backBuffer[0] = back;
5777 if (back)
5779 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5780 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5781 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5782 swapchain->presentParms.BackBufferCount = 1;
5784 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5785 back_impl->Flags |= SFLAG_SWAPCHAIN;
5787 else
5789 swapchain->presentParms.BackBufferCount = 0;
5790 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5791 swapchain->backBuffer = NULL;
5795 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5796 return WINED3D_OK;
5799 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 *ppZStencilSurface = This->stencilBufferTarget;
5802 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5804 if(*ppZStencilSurface != NULL) {
5805 /* Note inc ref on returned surface */
5806 IWineD3DSurface_AddRef(*ppZStencilSurface);
5807 return WINED3D_OK;
5808 } else {
5809 return WINED3DERR_NOTFOUND;
5813 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5814 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5817 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5818 const struct wined3d_gl_info *gl_info;
5819 struct wined3d_context *context;
5820 GLenum gl_filter;
5821 POINT offset = {0, 0};
5823 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5824 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5825 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5826 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5828 switch (filter) {
5829 case WINED3DTEXF_LINEAR:
5830 gl_filter = GL_LINEAR;
5831 break;
5833 default:
5834 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5835 case WINED3DTEXF_NONE:
5836 case WINED3DTEXF_POINT:
5837 gl_filter = GL_NEAREST;
5838 break;
5841 /* Make sure the drawables are up-to-date. Note that loading the
5842 * destination surface isn't strictly required if we overwrite the
5843 * entire surface. */
5844 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5845 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5847 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5848 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5849 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5851 if (!context->valid)
5853 context_release(context);
5854 WARN("Invalid context, skipping blit.\n");
5855 return;
5858 gl_info = context->gl_info;
5860 if (!surface_is_offscreen(src_surface))
5862 GLenum buffer = surface_get_gl_buffer(src_surface);
5864 TRACE("Source surface %p is onscreen\n", src_surface);
5866 if(buffer == GL_FRONT) {
5867 RECT windowsize;
5868 UINT h;
5869 ClientToScreen(context->win_handle, &offset);
5870 GetClientRect(context->win_handle, &windowsize);
5871 h = windowsize.bottom - windowsize.top;
5872 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5873 src_rect->y1 = offset.y + h - src_rect->y1;
5874 src_rect->y2 = offset.y + h - src_rect->y2;
5875 } else {
5876 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5877 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5880 ENTER_GL();
5881 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5882 glReadBuffer(buffer);
5883 checkGLcall("glReadBuffer()");
5884 } else {
5885 TRACE("Source surface %p is offscreen\n", src_surface);
5886 ENTER_GL();
5887 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5888 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5889 glReadBuffer(GL_COLOR_ATTACHMENT0);
5890 checkGLcall("glReadBuffer()");
5891 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5893 LEAVE_GL();
5895 /* Attach dst surface to dst fbo */
5896 if (!surface_is_offscreen(dst_surface))
5898 GLenum buffer = surface_get_gl_buffer(dst_surface);
5900 TRACE("Destination surface %p is onscreen\n", dst_surface);
5902 if(buffer == GL_FRONT) {
5903 RECT windowsize;
5904 UINT h;
5905 ClientToScreen(context->win_handle, &offset);
5906 GetClientRect(context->win_handle, &windowsize);
5907 h = windowsize.bottom - windowsize.top;
5908 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5909 dst_rect->y1 = offset.y + h - dst_rect->y1;
5910 dst_rect->y2 = offset.y + h - dst_rect->y2;
5911 } else {
5912 /* Screen coords = window coords, surface height = window height */
5913 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5914 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5917 ENTER_GL();
5918 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5919 context_set_draw_buffer(context, buffer);
5921 else
5923 TRACE("Destination surface %p is offscreen\n", dst_surface);
5925 ENTER_GL();
5926 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5927 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5928 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5929 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5931 glDisable(GL_SCISSOR_TEST);
5932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5934 if (flip) {
5935 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5936 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5937 checkGLcall("glBlitFramebuffer()");
5938 } else {
5939 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5940 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5941 checkGLcall("glBlitFramebuffer()");
5944 LEAVE_GL();
5946 wglFlush(); /* Flush to ensure ordering across contexts. */
5948 context_release(context);
5950 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5953 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5954 BOOL set_viewport) {
5955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5957 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5959 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5961 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5962 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5963 return WINED3DERR_INVALIDCALL;
5966 /* MSDN says that null disables the render target
5967 but a device must always be associated with a render target
5968 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5970 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5971 FIXME("Trying to set render target 0 to NULL\n");
5972 return WINED3DERR_INVALIDCALL;
5974 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5975 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);
5976 return WINED3DERR_INVALIDCALL;
5979 /* If we are trying to set what we already have, don't bother */
5980 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5981 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5982 return WINED3D_OK;
5984 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5985 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5986 This->render_targets[RenderTargetIndex] = pRenderTarget;
5988 /* Render target 0 is special */
5989 if(RenderTargetIndex == 0 && set_viewport) {
5990 /* Finally, reset the viewport and scissor rect as the MSDN states.
5991 * Tests show that stateblock recording is ignored, the change goes
5992 * directly into the primary stateblock.
5994 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5995 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5996 This->stateBlock->viewport.X = 0;
5997 This->stateBlock->viewport.Y = 0;
5998 This->stateBlock->viewport.MaxZ = 1.0f;
5999 This->stateBlock->viewport.MinZ = 0.0f;
6000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6002 This->stateBlock->scissorRect.top = 0;
6003 This->stateBlock->scissorRect.left = 0;
6004 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6005 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6008 return WINED3D_OK;
6011 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6013 HRESULT hr = WINED3D_OK;
6014 IWineD3DSurface *tmp;
6016 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6018 if (pNewZStencil == This->stencilBufferTarget) {
6019 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6020 } else {
6021 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6022 * depending on the renter target implementation being used.
6023 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6024 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6025 * stencil buffer and incur an extra memory overhead
6026 ******************************************************/
6028 if (This->stencilBufferTarget) {
6029 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6030 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6031 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6032 } else {
6033 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6034 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6035 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6036 context_release(context);
6040 tmp = This->stencilBufferTarget;
6041 This->stencilBufferTarget = pNewZStencil;
6042 /* should we be calling the parent or the wined3d surface? */
6043 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6044 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6045 hr = WINED3D_OK;
6047 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6048 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6055 return hr;
6058 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6059 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6061 /* TODO: the use of Impl is deprecated. */
6062 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6063 WINED3DLOCKED_RECT lockedRect;
6065 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6067 /* some basic validation checks */
6068 if(This->cursorTexture) {
6069 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6070 ENTER_GL();
6071 glDeleteTextures(1, &This->cursorTexture);
6072 LEAVE_GL();
6073 context_release(context);
6074 This->cursorTexture = 0;
6077 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6078 This->haveHardwareCursor = TRUE;
6079 else
6080 This->haveHardwareCursor = FALSE;
6082 if(pCursorBitmap) {
6083 WINED3DLOCKED_RECT rect;
6085 /* MSDN: Cursor must be A8R8G8B8 */
6086 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6088 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6089 return WINED3DERR_INVALIDCALL;
6092 /* MSDN: Cursor must be smaller than the display mode */
6093 if(pSur->currentDesc.Width > This->ddraw_width ||
6094 pSur->currentDesc.Height > This->ddraw_height) {
6095 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);
6096 return WINED3DERR_INVALIDCALL;
6099 if (!This->haveHardwareCursor) {
6100 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6102 /* Do not store the surface's pointer because the application may
6103 * release it after setting the cursor image. Windows doesn't
6104 * addref the set surface, so we can't do this either without
6105 * creating circular refcount dependencies. Copy out the gl texture
6106 * instead.
6108 This->cursorWidth = pSur->currentDesc.Width;
6109 This->cursorHeight = pSur->currentDesc.Height;
6110 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6112 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6113 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6114 struct wined3d_context *context;
6115 char *mem, *bits = rect.pBits;
6116 GLint intfmt = glDesc->glInternal;
6117 GLint format = glDesc->glFormat;
6118 GLint type = glDesc->glType;
6119 INT height = This->cursorHeight;
6120 INT width = This->cursorWidth;
6121 INT bpp = glDesc->byte_count;
6122 DWORD sampler;
6123 INT i;
6125 /* Reformat the texture memory (pitch and width can be
6126 * different) */
6127 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6128 for(i = 0; i < height; i++)
6129 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6130 IWineD3DSurface_UnlockRect(pCursorBitmap);
6132 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6134 ENTER_GL();
6136 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6138 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6139 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6142 /* Make sure that a proper texture unit is selected */
6143 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6144 checkGLcall("glActiveTextureARB");
6145 sampler = This->rev_tex_unit_map[0];
6146 if (sampler != WINED3D_UNMAPPED_STAGE)
6148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6150 /* Create a new cursor texture */
6151 glGenTextures(1, &This->cursorTexture);
6152 checkGLcall("glGenTextures");
6153 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6154 checkGLcall("glBindTexture");
6155 /* Copy the bitmap memory into the cursor texture */
6156 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6157 HeapFree(GetProcessHeap(), 0, mem);
6158 checkGLcall("glTexImage2D");
6160 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6162 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6163 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6166 LEAVE_GL();
6168 context_release(context);
6170 else
6172 FIXME("A cursor texture was not returned.\n");
6173 This->cursorTexture = 0;
6176 else
6178 /* Draw a hardware cursor */
6179 ICONINFO cursorInfo;
6180 HCURSOR cursor;
6181 /* Create and clear maskBits because it is not needed for
6182 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6183 * chunks. */
6184 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6185 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6186 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6187 WINED3DLOCK_NO_DIRTY_UPDATE |
6188 WINED3DLOCK_READONLY
6190 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6191 pSur->currentDesc.Height);
6193 cursorInfo.fIcon = FALSE;
6194 cursorInfo.xHotspot = XHotSpot;
6195 cursorInfo.yHotspot = YHotSpot;
6196 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6197 1, 1, maskBits);
6198 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6199 1, 32, lockedRect.pBits);
6200 IWineD3DSurface_UnlockRect(pCursorBitmap);
6201 /* Create our cursor and clean up. */
6202 cursor = CreateIconIndirect(&cursorInfo);
6203 SetCursor(cursor);
6204 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6205 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6206 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6207 This->hardwareCursor = cursor;
6208 HeapFree(GetProcessHeap(), 0, maskBits);
6212 This->xHotSpot = XHotSpot;
6213 This->yHotSpot = YHotSpot;
6214 return WINED3D_OK;
6217 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6219 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6221 This->xScreenSpace = XScreenSpace;
6222 This->yScreenSpace = YScreenSpace;
6224 return;
6228 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6230 BOOL oldVisible = This->bCursorVisible;
6231 POINT pt;
6233 TRACE("(%p) : visible(%d)\n", This, bShow);
6236 * When ShowCursor is first called it should make the cursor appear at the OS's last
6237 * known cursor position. Because of this, some applications just repetitively call
6238 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6240 GetCursorPos(&pt);
6241 This->xScreenSpace = pt.x;
6242 This->yScreenSpace = pt.y;
6244 if (This->haveHardwareCursor) {
6245 This->bCursorVisible = bShow;
6246 if (bShow)
6247 SetCursor(This->hardwareCursor);
6248 else
6249 SetCursor(NULL);
6251 else
6253 if (This->cursorTexture)
6254 This->bCursorVisible = bShow;
6257 return oldVisible;
6260 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6261 TRACE("checking resource %p for eviction\n", resource);
6262 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6263 TRACE("Evicting %p\n", resource);
6264 IWineD3DResource_UnLoad(resource);
6266 IWineD3DResource_Release(resource);
6267 return S_OK;
6270 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6272 TRACE("iface %p.\n", iface);
6274 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6275 return WINED3D_OK;
6278 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6280 IWineD3DDeviceImpl *device = surface->resource.device;
6281 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6283 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6284 if(surface->Flags & SFLAG_DIBSECTION) {
6285 /* Release the DC */
6286 SelectObject(surface->hDC, surface->dib.holdbitmap);
6287 DeleteDC(surface->hDC);
6288 /* Release the DIB section */
6289 DeleteObject(surface->dib.DIBsection);
6290 surface->dib.bitmap_data = NULL;
6291 surface->resource.allocatedMemory = NULL;
6292 surface->Flags &= ~SFLAG_DIBSECTION;
6294 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6295 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6296 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6297 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6299 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6300 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6301 } else {
6302 surface->pow2Width = surface->pow2Height = 1;
6303 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6304 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6306 surface->glRect.left = 0;
6307 surface->glRect.top = 0;
6308 surface->glRect.right = surface->pow2Width;
6309 surface->glRect.bottom = surface->pow2Height;
6311 if (surface->texture_name)
6313 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6314 ENTER_GL();
6315 glDeleteTextures(1, &surface->texture_name);
6316 LEAVE_GL();
6317 context_release(context);
6318 surface->texture_name = 0;
6319 surface->Flags &= ~SFLAG_CLIENT;
6321 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6322 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6323 surface->Flags |= SFLAG_NONPOW2;
6324 } else {
6325 surface->Flags &= ~SFLAG_NONPOW2;
6327 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6328 surface->resource.allocatedMemory = NULL;
6329 surface->resource.heapMemory = NULL;
6330 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6332 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6333 * to a FBO */
6334 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6336 return E_OUTOFMEMORY;
6338 return WINED3D_OK;
6341 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6342 TRACE("Unloading resource %p\n", resource);
6343 IWineD3DResource_UnLoad(resource);
6344 IWineD3DResource_Release(resource);
6345 return S_OK;
6348 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6350 UINT i, count;
6351 WINED3DDISPLAYMODE m;
6352 HRESULT hr;
6354 /* All Windowed modes are supported, as is leaving the current mode */
6355 if(pp->Windowed) return TRUE;
6356 if(!pp->BackBufferWidth) return TRUE;
6357 if(!pp->BackBufferHeight) return TRUE;
6359 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6360 for(i = 0; i < count; i++) {
6361 memset(&m, 0, sizeof(m));
6362 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6363 if(FAILED(hr)) {
6364 ERR("EnumAdapterModes failed\n");
6366 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6367 /* Mode found, it is supported */
6368 return TRUE;
6371 /* Mode not found -> not supported */
6372 return FALSE;
6375 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6377 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6378 const struct wined3d_gl_info *gl_info;
6379 struct wined3d_context *context;
6380 IWineD3DBaseShaderImpl *shader;
6382 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6383 gl_info = context->gl_info;
6385 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6386 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6387 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6390 ENTER_GL();
6391 if(This->depth_blt_texture) {
6392 glDeleteTextures(1, &This->depth_blt_texture);
6393 This->depth_blt_texture = 0;
6395 if (This->depth_blt_rb) {
6396 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6397 This->depth_blt_rb = 0;
6398 This->depth_blt_rb_w = 0;
6399 This->depth_blt_rb_h = 0;
6401 LEAVE_GL();
6403 This->blitter->free_private(iface);
6404 This->frag_pipe->free_private(iface);
6405 This->shader_backend->shader_free_private(iface);
6406 destroy_dummy_textures(This, gl_info);
6408 context_release(context);
6410 while (This->numContexts)
6412 context_destroy(This, This->contexts[0]);
6414 HeapFree(GetProcessHeap(), 0, swapchain->context);
6415 swapchain->context = NULL;
6416 swapchain->num_contexts = 0;
6419 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6421 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6422 struct wined3d_context *context;
6423 HRESULT hr;
6424 IWineD3DSurfaceImpl *target;
6426 /* Recreate the primary swapchain's context */
6427 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6428 if (!swapchain->context)
6430 ERR("Failed to allocate memory for swapchain context array.\n");
6431 return E_OUTOFMEMORY;
6434 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6435 if (!(context = context_create(swapchain, target)))
6437 WARN("Failed to create context.\n");
6438 HeapFree(GetProcessHeap(), 0, swapchain->context);
6439 return E_FAIL;
6442 swapchain->context[0] = context;
6443 swapchain->num_contexts = 1;
6444 create_dummy_textures(This);
6445 context_release(context);
6447 hr = This->shader_backend->shader_alloc_private(iface);
6448 if (FAILED(hr))
6450 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6451 goto err;
6454 hr = This->frag_pipe->alloc_private(iface);
6455 if (FAILED(hr))
6457 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6458 This->shader_backend->shader_free_private(iface);
6459 goto err;
6462 hr = This->blitter->alloc_private(iface);
6463 if (FAILED(hr))
6465 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6466 This->frag_pipe->free_private(iface);
6467 This->shader_backend->shader_free_private(iface);
6468 goto err;
6471 return WINED3D_OK;
6473 err:
6474 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6475 destroy_dummy_textures(This, context->gl_info);
6476 context_release(context);
6477 context_destroy(This, context);
6478 HeapFree(GetProcessHeap(), 0, swapchain->context);
6479 swapchain->num_contexts = 0;
6480 return hr;
6483 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6485 IWineD3DSwapChainImpl *swapchain;
6486 HRESULT hr;
6487 BOOL DisplayModeChanged = FALSE;
6488 WINED3DDISPLAYMODE mode;
6489 TRACE("(%p)\n", This);
6491 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6492 if(FAILED(hr)) {
6493 ERR("Failed to get the first implicit swapchain\n");
6494 return hr;
6497 if(!is_display_mode_supported(This, pPresentationParameters)) {
6498 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6499 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6500 pPresentationParameters->BackBufferHeight);
6501 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6502 return WINED3DERR_INVALIDCALL;
6505 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6506 * on an existing gl context, so there's no real need for recreation.
6508 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6510 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6512 TRACE("New params:\n");
6513 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6514 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6515 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6516 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6517 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6518 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6519 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6520 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6521 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6522 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6523 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6524 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6525 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6527 /* No special treatment of these parameters. Just store them */
6528 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6529 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6530 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6531 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6533 /* What to do about these? */
6534 if(pPresentationParameters->BackBufferCount != 0 &&
6535 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6536 ERR("Cannot change the back buffer count yet\n");
6538 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6539 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6540 ERR("Cannot change the back buffer format yet\n");
6542 if(pPresentationParameters->hDeviceWindow != NULL &&
6543 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6544 ERR("Cannot change the device window yet\n");
6546 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6547 HRESULT hrc;
6549 TRACE("Creating the depth stencil buffer\n");
6551 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6552 This->parent,
6553 pPresentationParameters->BackBufferWidth,
6554 pPresentationParameters->BackBufferHeight,
6555 pPresentationParameters->AutoDepthStencilFormat,
6556 pPresentationParameters->MultiSampleType,
6557 pPresentationParameters->MultiSampleQuality,
6558 FALSE,
6559 &This->auto_depth_stencil_buffer);
6561 if (FAILED(hrc)) {
6562 ERR("Failed to create the depth stencil buffer\n");
6563 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6564 return WINED3DERR_INVALIDCALL;
6568 /* Reset the depth stencil */
6569 if (pPresentationParameters->EnableAutoDepthStencil)
6570 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6571 else
6572 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6574 TRACE("Resetting stateblock\n");
6575 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6576 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6578 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6580 if(pPresentationParameters->Windowed) {
6581 mode.Width = swapchain->orig_width;
6582 mode.Height = swapchain->orig_height;
6583 mode.RefreshRate = 0;
6584 mode.Format = swapchain->presentParms.BackBufferFormat;
6585 } else {
6586 mode.Width = pPresentationParameters->BackBufferWidth;
6587 mode.Height = pPresentationParameters->BackBufferHeight;
6588 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6589 mode.Format = swapchain->presentParms.BackBufferFormat;
6592 /* Should Width == 800 && Height == 0 set 800x600? */
6593 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6594 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6595 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6597 UINT i;
6599 if(!pPresentationParameters->Windowed) {
6600 DisplayModeChanged = TRUE;
6602 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6603 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6605 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6606 if(FAILED(hr))
6608 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6609 return hr;
6612 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6613 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6614 if(FAILED(hr))
6616 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6617 return hr;
6620 if(This->auto_depth_stencil_buffer) {
6621 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6622 if(FAILED(hr))
6624 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6625 return hr;
6630 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6631 || DisplayModeChanged)
6633 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6635 if (!pPresentationParameters->Windowed)
6637 if(swapchain->presentParms.Windowed) {
6638 /* switch from windowed to fs */
6639 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6640 pPresentationParameters->BackBufferHeight);
6641 } else {
6642 /* Fullscreen -> fullscreen mode change */
6643 MoveWindow(swapchain->device_window, 0, 0,
6644 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6645 TRUE);
6648 else if (!swapchain->presentParms.Windowed)
6650 /* Fullscreen -> windowed switch */
6651 swapchain_restore_fullscreen_window(swapchain);
6653 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6654 } else if(!pPresentationParameters->Windowed) {
6655 DWORD style = This->style, exStyle = This->exStyle;
6656 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6657 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6658 * Reset to clear up their mess. Guild Wars also loses the device during that.
6660 This->style = 0;
6661 This->exStyle = 0;
6662 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6663 pPresentationParameters->BackBufferHeight);
6664 This->style = style;
6665 This->exStyle = exStyle;
6668 /* Note: No parent needed for initial internal stateblock */
6669 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6670 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6671 else TRACE("Created stateblock %p\n", This->stateBlock);
6672 This->updateStateBlock = This->stateBlock;
6673 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6675 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6676 if(FAILED(hr)) {
6677 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6680 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6682 RECT client_rect;
6683 GetClientRect(swapchain->win_handle, &client_rect);
6685 if(!swapchain->presentParms.BackBufferCount)
6687 TRACE("Single buffered rendering\n");
6688 swapchain->render_to_fbo = FALSE;
6690 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6691 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6693 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6694 swapchain->presentParms.BackBufferWidth,
6695 swapchain->presentParms.BackBufferHeight,
6696 client_rect.right, client_rect.bottom);
6697 swapchain->render_to_fbo = TRUE;
6699 else
6701 TRACE("Rendering directly to GL_BACK\n");
6702 swapchain->render_to_fbo = FALSE;
6706 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6707 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6709 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6710 * first use
6712 return hr;
6715 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6717 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6719 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6721 return WINED3D_OK;
6725 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6727 TRACE("(%p) : pParameters %p\n", This, pParameters);
6729 *pParameters = This->createParms;
6730 return WINED3D_OK;
6733 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6734 IWineD3DSwapChain *swapchain;
6736 TRACE("Relaying to swapchain\n");
6738 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6739 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6740 IWineD3DSwapChain_Release(swapchain);
6744 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6745 IWineD3DSwapChain *swapchain;
6747 TRACE("Relaying to swapchain\n");
6749 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6750 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6751 IWineD3DSwapChain_Release(swapchain);
6756 /** ********************************************************
6757 * Notification functions
6758 ** ********************************************************/
6759 /** This function must be called in the release of a resource when ref == 0,
6760 * the contents of resource must still be correct,
6761 * any handles to other resource held by the caller must be closed
6762 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6763 *****************************************************/
6764 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6766 TRACE("(%p) : Adding resource %p\n", This, resource);
6768 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6771 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6773 TRACE("(%p) : Removing resource %p\n", This, resource);
6775 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6778 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6780 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6781 int counter;
6783 TRACE("(%p) : resource %p\n", This, resource);
6785 context_resource_released((IWineD3DDevice *)This, resource, type);
6787 switch (type) {
6788 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6789 case WINED3DRTYPE_SURFACE: {
6790 unsigned int i;
6792 if (This->d3d_initialized)
6794 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6796 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6797 This->render_targets[i] = NULL;
6800 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6801 This->stencilBufferTarget = NULL;
6805 break;
6807 case WINED3DRTYPE_TEXTURE:
6808 case WINED3DRTYPE_CUBETEXTURE:
6809 case WINED3DRTYPE_VOLUMETEXTURE:
6810 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6811 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6812 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6813 This->stateBlock->textures[counter] = NULL;
6815 if (This->updateStateBlock != This->stateBlock ){
6816 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6817 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6818 This->updateStateBlock->textures[counter] = NULL;
6822 break;
6823 case WINED3DRTYPE_VOLUME:
6824 /* TODO: nothing really? */
6825 break;
6826 case WINED3DRTYPE_BUFFER:
6828 int streamNumber;
6829 TRACE("Cleaning up stream pointers\n");
6831 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6832 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6833 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6835 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6836 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6837 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6838 This->updateStateBlock->streamSource[streamNumber] = 0;
6839 /* Set changed flag? */
6842 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) */
6843 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6844 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6845 This->stateBlock->streamSource[streamNumber] = 0;
6850 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6851 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6852 This->updateStateBlock->pIndexData = NULL;
6855 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6856 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6857 This->stateBlock->pIndexData = NULL;
6861 break;
6863 default:
6864 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6865 break;
6869 /* Remove the resource from the resourceStore */
6870 device_resource_remove(This, resource);
6872 TRACE("Resource released\n");
6876 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6878 IWineD3DResourceImpl *resource, *cursor;
6879 HRESULT ret;
6880 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6882 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6883 TRACE("enumerating resource %p\n", resource);
6884 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6885 ret = pCallback((IWineD3DResource *) resource, pData);
6886 if(ret == S_FALSE) {
6887 TRACE("Canceling enumeration\n");
6888 break;
6891 return WINED3D_OK;
6894 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6897 IWineD3DResourceImpl *resource;
6899 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6901 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6902 if (type == WINED3DRTYPE_SURFACE)
6904 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6906 TRACE("Found surface %p for dc %p.\n", resource, dc);
6907 *surface = (IWineD3DSurface *)resource;
6908 return WINED3D_OK;
6913 return WINED3DERR_INVALIDCALL;
6916 /**********************************************************
6917 * IWineD3DDevice VTbl follows
6918 **********************************************************/
6920 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6922 /*** IUnknown methods ***/
6923 IWineD3DDeviceImpl_QueryInterface,
6924 IWineD3DDeviceImpl_AddRef,
6925 IWineD3DDeviceImpl_Release,
6926 /*** IWineD3DDevice methods ***/
6927 IWineD3DDeviceImpl_GetParent,
6928 /*** Creation methods**/
6929 IWineD3DDeviceImpl_CreateBuffer,
6930 IWineD3DDeviceImpl_CreateVertexBuffer,
6931 IWineD3DDeviceImpl_CreateIndexBuffer,
6932 IWineD3DDeviceImpl_CreateStateBlock,
6933 IWineD3DDeviceImpl_CreateSurface,
6934 IWineD3DDeviceImpl_CreateRendertargetView,
6935 IWineD3DDeviceImpl_CreateTexture,
6936 IWineD3DDeviceImpl_CreateVolumeTexture,
6937 IWineD3DDeviceImpl_CreateVolume,
6938 IWineD3DDeviceImpl_CreateCubeTexture,
6939 IWineD3DDeviceImpl_CreateQuery,
6940 IWineD3DDeviceImpl_CreateSwapChain,
6941 IWineD3DDeviceImpl_CreateVertexDeclaration,
6942 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6943 IWineD3DDeviceImpl_CreateVertexShader,
6944 IWineD3DDeviceImpl_CreateGeometryShader,
6945 IWineD3DDeviceImpl_CreatePixelShader,
6946 IWineD3DDeviceImpl_CreatePalette,
6947 /*** Odd functions **/
6948 IWineD3DDeviceImpl_Init3D,
6949 IWineD3DDeviceImpl_InitGDI,
6950 IWineD3DDeviceImpl_Uninit3D,
6951 IWineD3DDeviceImpl_UninitGDI,
6952 IWineD3DDeviceImpl_SetMultithreaded,
6953 IWineD3DDeviceImpl_EvictManagedResources,
6954 IWineD3DDeviceImpl_GetAvailableTextureMem,
6955 IWineD3DDeviceImpl_GetBackBuffer,
6956 IWineD3DDeviceImpl_GetCreationParameters,
6957 IWineD3DDeviceImpl_GetDeviceCaps,
6958 IWineD3DDeviceImpl_GetDirect3D,
6959 IWineD3DDeviceImpl_GetDisplayMode,
6960 IWineD3DDeviceImpl_SetDisplayMode,
6961 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6962 IWineD3DDeviceImpl_GetRasterStatus,
6963 IWineD3DDeviceImpl_GetSwapChain,
6964 IWineD3DDeviceImpl_Reset,
6965 IWineD3DDeviceImpl_SetDialogBoxMode,
6966 IWineD3DDeviceImpl_SetCursorProperties,
6967 IWineD3DDeviceImpl_SetCursorPosition,
6968 IWineD3DDeviceImpl_ShowCursor,
6969 /*** Getters and setters **/
6970 IWineD3DDeviceImpl_SetClipPlane,
6971 IWineD3DDeviceImpl_GetClipPlane,
6972 IWineD3DDeviceImpl_SetClipStatus,
6973 IWineD3DDeviceImpl_GetClipStatus,
6974 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6975 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6976 IWineD3DDeviceImpl_SetDepthStencilSurface,
6977 IWineD3DDeviceImpl_GetDepthStencilSurface,
6978 IWineD3DDeviceImpl_SetGammaRamp,
6979 IWineD3DDeviceImpl_GetGammaRamp,
6980 IWineD3DDeviceImpl_SetIndexBuffer,
6981 IWineD3DDeviceImpl_GetIndexBuffer,
6982 IWineD3DDeviceImpl_SetBaseVertexIndex,
6983 IWineD3DDeviceImpl_GetBaseVertexIndex,
6984 IWineD3DDeviceImpl_SetLight,
6985 IWineD3DDeviceImpl_GetLight,
6986 IWineD3DDeviceImpl_SetLightEnable,
6987 IWineD3DDeviceImpl_GetLightEnable,
6988 IWineD3DDeviceImpl_SetMaterial,
6989 IWineD3DDeviceImpl_GetMaterial,
6990 IWineD3DDeviceImpl_SetNPatchMode,
6991 IWineD3DDeviceImpl_GetNPatchMode,
6992 IWineD3DDeviceImpl_SetPaletteEntries,
6993 IWineD3DDeviceImpl_GetPaletteEntries,
6994 IWineD3DDeviceImpl_SetPixelShader,
6995 IWineD3DDeviceImpl_GetPixelShader,
6996 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6997 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6998 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6999 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7000 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7001 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7002 IWineD3DDeviceImpl_SetRenderState,
7003 IWineD3DDeviceImpl_GetRenderState,
7004 IWineD3DDeviceImpl_SetRenderTarget,
7005 IWineD3DDeviceImpl_GetRenderTarget,
7006 IWineD3DDeviceImpl_SetFrontBackBuffers,
7007 IWineD3DDeviceImpl_SetSamplerState,
7008 IWineD3DDeviceImpl_GetSamplerState,
7009 IWineD3DDeviceImpl_SetScissorRect,
7010 IWineD3DDeviceImpl_GetScissorRect,
7011 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7012 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7013 IWineD3DDeviceImpl_SetStreamSource,
7014 IWineD3DDeviceImpl_GetStreamSource,
7015 IWineD3DDeviceImpl_SetStreamSourceFreq,
7016 IWineD3DDeviceImpl_GetStreamSourceFreq,
7017 IWineD3DDeviceImpl_SetTexture,
7018 IWineD3DDeviceImpl_GetTexture,
7019 IWineD3DDeviceImpl_SetTextureStageState,
7020 IWineD3DDeviceImpl_GetTextureStageState,
7021 IWineD3DDeviceImpl_SetTransform,
7022 IWineD3DDeviceImpl_GetTransform,
7023 IWineD3DDeviceImpl_SetVertexDeclaration,
7024 IWineD3DDeviceImpl_GetVertexDeclaration,
7025 IWineD3DDeviceImpl_SetVertexShader,
7026 IWineD3DDeviceImpl_GetVertexShader,
7027 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7028 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7029 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7030 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7031 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7032 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7033 IWineD3DDeviceImpl_SetViewport,
7034 IWineD3DDeviceImpl_GetViewport,
7035 IWineD3DDeviceImpl_MultiplyTransform,
7036 IWineD3DDeviceImpl_ValidateDevice,
7037 IWineD3DDeviceImpl_ProcessVertices,
7038 /*** State block ***/
7039 IWineD3DDeviceImpl_BeginStateBlock,
7040 IWineD3DDeviceImpl_EndStateBlock,
7041 /*** Scene management ***/
7042 IWineD3DDeviceImpl_BeginScene,
7043 IWineD3DDeviceImpl_EndScene,
7044 IWineD3DDeviceImpl_Present,
7045 IWineD3DDeviceImpl_Clear,
7046 IWineD3DDeviceImpl_ClearRendertargetView,
7047 /*** Drawing ***/
7048 IWineD3DDeviceImpl_SetPrimitiveType,
7049 IWineD3DDeviceImpl_GetPrimitiveType,
7050 IWineD3DDeviceImpl_DrawPrimitive,
7051 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7052 IWineD3DDeviceImpl_DrawPrimitiveUP,
7053 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7054 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7055 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7056 IWineD3DDeviceImpl_DrawRectPatch,
7057 IWineD3DDeviceImpl_DrawTriPatch,
7058 IWineD3DDeviceImpl_DeletePatch,
7059 IWineD3DDeviceImpl_ColorFill,
7060 IWineD3DDeviceImpl_UpdateTexture,
7061 IWineD3DDeviceImpl_UpdateSurface,
7062 IWineD3DDeviceImpl_GetFrontBufferData,
7063 /*** object tracking ***/
7064 IWineD3DDeviceImpl_EnumResources,
7065 IWineD3DDeviceImpl_GetSurfaceFromDC,
7066 IWineD3DDeviceImpl_AcquireFocusWindow,
7067 IWineD3DDeviceImpl_ReleaseFocusWindow,
7070 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7071 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7072 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7074 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7075 const struct fragment_pipeline *fragment_pipeline;
7076 struct shader_caps shader_caps;
7077 struct fragment_caps ffp_caps;
7078 WINED3DDISPLAYMODE mode;
7079 unsigned int i;
7080 HRESULT hr;
7082 device->lpVtbl = &IWineD3DDevice_Vtbl;
7083 device->ref = 1;
7084 device->wined3d = (IWineD3D *)wined3d;
7085 IWineD3D_AddRef(device->wined3d);
7086 device->adapter = wined3d->adapter_count ? adapter : NULL;
7087 device->parent = parent;
7088 device->device_parent = device_parent;
7089 list_init(&device->resources);
7090 list_init(&device->shaders);
7092 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7093 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7095 /* Get the initial screen setup for ddraw. */
7096 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7097 if (FAILED(hr))
7099 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7100 IWineD3D_Release(device->wined3d);
7101 return hr;
7103 device->ddraw_width = mode.Width;
7104 device->ddraw_height = mode.Height;
7105 device->ddraw_format = mode.Format;
7107 /* Save the creation parameters. */
7108 device->createParms.AdapterOrdinal = adapter_idx;
7109 device->createParms.DeviceType = device_type;
7110 device->createParms.hFocusWindow = focus_window;
7111 device->createParms.BehaviorFlags = flags;
7113 device->devType = device_type;
7114 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7116 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7117 device->shader_backend = adapter->shader_backend;
7119 memset(&shader_caps, 0, sizeof(shader_caps));
7120 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7121 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7122 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7123 device->vs_clipping = shader_caps.VSClipping;
7125 memset(&ffp_caps, 0, sizeof(ffp_caps));
7126 fragment_pipeline = adapter->fragment_pipe;
7127 device->frag_pipe = fragment_pipeline;
7128 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7129 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7131 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7132 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7133 if (FAILED(hr))
7135 ERR("Failed to compile state table, hr %#x.\n", hr);
7136 IWineD3D_Release(device->wined3d);
7137 return hr;
7140 device->blitter = adapter->blitter;
7142 return WINED3D_OK;
7146 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7147 DWORD rep = This->StateTable[state].representative;
7148 struct wined3d_context *context;
7149 DWORD idx;
7150 BYTE shift;
7151 UINT i;
7153 for(i = 0; i < This->numContexts; i++) {
7154 context = This->contexts[i];
7155 if(isStateDirty(context, rep)) continue;
7157 context->dirtyArray[context->numDirtyEntries++] = rep;
7158 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7159 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7160 context->isStateDirty[idx] |= (1 << shift);
7164 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7166 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7167 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7168 *width = surface->pow2Width;
7169 *height = surface->pow2Height;
7172 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7174 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7175 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7176 * current context's drawable, which is the size of the back buffer of the swapchain
7177 * the active context belongs to. */
7178 *width = swapchain->presentParms.BackBufferWidth;
7179 *height = swapchain->presentParms.BackBufferHeight;
7182 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7183 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7185 if (device->filter_messages)
7187 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7188 window, message, wparam, lparam);
7189 return DefWindowProcW(window, message, wparam, lparam);
7192 if (message == WM_DESTROY)
7194 TRACE("unregister window %p.\n", window);
7195 wined3d_unregister_window(window);
7197 if (device->focus_window == window) device->focus_window = NULL;
7198 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7201 return CallWindowProcW(proc, window, message, wparam, lparam);