push 6e61d6ca5bcaf95ac09a664b4ba4f88238c927be
[wine/hacks.git] / dlls / wined3d / device.c
blob6682aa4635eb2ccae5f5e5f498757f7240a899d4
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 /**********************************************************
498 * IUnknown parts follows
499 **********************************************************/
501 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
505 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
506 if (IsEqualGUID(riid, &IID_IUnknown)
507 || IsEqualGUID(riid, &IID_IWineD3DBase)
508 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
509 IUnknown_AddRef(iface);
510 *ppobj = This;
511 return S_OK;
513 *ppobj = NULL;
514 return E_NOINTERFACE;
517 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
519 ULONG refCount = InterlockedIncrement(&This->ref);
521 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
522 return refCount;
525 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
527 ULONG refCount = InterlockedDecrement(&This->ref);
529 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
531 if (!refCount) {
532 UINT i;
534 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
535 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
536 This->multistate_funcs[i] = NULL;
539 /* TODO: Clean up all the surfaces and textures! */
540 /* NOTE: You must release the parent if the object was created via a callback
541 ** ***************************/
543 if (!list_empty(&This->resources)) {
544 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
545 dumpResources(&This->resources);
548 if(This->contexts) ERR("Context array not freed!\n");
549 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
550 This->haveHardwareCursor = FALSE;
552 IWineD3D_Release(This->wined3d);
553 This->wined3d = NULL;
554 HeapFree(GetProcessHeap(), 0, This);
555 TRACE("Freed device %p\n", This);
556 This = NULL;
558 return refCount;
561 /**********************************************************
562 * IWineD3DDevice implementation follows
563 **********************************************************/
564 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 *pParent = This->parent;
567 IUnknown_AddRef(This->parent);
568 return WINED3D_OK;
571 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
572 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
575 struct wined3d_buffer *object;
576 HRESULT hr;
578 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
580 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
581 if (!object)
583 ERR("Failed to allocate memory\n");
584 return E_OUTOFMEMORY;
587 FIXME("Ignoring access flags (pool)\n");
589 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
590 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
591 if (FAILED(hr))
593 WARN("Failed to initialize buffer, hr %#x.\n", hr);
594 HeapFree(GetProcessHeap(), 0, object);
595 return hr;
597 object->desc = *desc;
599 TRACE("Created buffer %p.\n", object);
601 *buffer = (IWineD3DBuffer *)object;
603 return WINED3D_OK;
606 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
607 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
608 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
611 struct wined3d_buffer *object;
612 HRESULT hr;
614 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
615 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
617 if (Pool == WINED3DPOOL_SCRATCH)
619 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
620 * anyway, SCRATCH vertex buffers aren't usable anywhere
622 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
623 *ppVertexBuffer = NULL;
624 return WINED3DERR_INVALIDCALL;
627 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
628 if (!object)
630 ERR("Out of memory\n");
631 *ppVertexBuffer = NULL;
632 return WINED3DERR_OUTOFVIDEOMEMORY;
635 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
636 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
637 if (FAILED(hr))
639 WARN("Failed to initialize buffer, hr %#x.\n", hr);
640 HeapFree(GetProcessHeap(), 0, object);
641 return hr;
644 TRACE("Created buffer %p.\n", object);
645 *ppVertexBuffer = (IWineD3DBuffer *)object;
647 return WINED3D_OK;
650 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
651 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
652 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
655 struct wined3d_buffer *object;
656 HRESULT hr;
658 TRACE("(%p) Creating index buffer\n", This);
660 /* Allocate the storage for the device */
661 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
662 if (!object)
664 ERR("Out of memory\n");
665 *ppIndexBuffer = NULL;
666 return WINED3DERR_OUTOFVIDEOMEMORY;
669 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
670 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
671 parent, parent_ops);
672 if (FAILED(hr))
674 WARN("Failed to initialize buffer, hr %#x\n", hr);
675 HeapFree(GetProcessHeap(), 0, object);
676 return hr;
679 TRACE("Created buffer %p.\n", object);
681 *ppIndexBuffer = (IWineD3DBuffer *) object;
683 return WINED3D_OK;
686 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
687 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
690 IWineD3DStateBlockImpl *object;
691 HRESULT hr;
693 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
694 if(!object)
696 ERR("Failed to allocate stateblock memory.\n");
697 return E_OUTOFMEMORY;
700 hr = stateblock_init(object, This, type);
701 if (FAILED(hr))
703 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
704 HeapFree(GetProcessHeap(), 0, object);
705 return hr;
708 TRACE("Created stateblock %p.\n", object);
709 *stateblock = (IWineD3DStateBlock *)object;
711 return WINED3D_OK;
714 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
715 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
716 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
717 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
720 IWineD3DSurfaceImpl *object;
721 HRESULT hr;
723 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
724 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
725 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
726 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
727 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
729 if (Impl == SURFACE_OPENGL && !This->adapter)
731 ERR("OpenGL surfaces are not available without OpenGL.\n");
732 return WINED3DERR_NOTAVAILABLE;
735 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
736 if (!object)
738 ERR("Failed to allocate surface memory.\n");
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
743 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
744 if (FAILED(hr))
746 WARN("Failed to initialize surface, returning %#x.\n", hr);
747 HeapFree(GetProcessHeap(), 0, object);
748 return hr;
751 TRACE("(%p) : Created surface %p\n", This, object);
753 *ppSurface = (IWineD3DSurface *)object;
755 return hr;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
759 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
761 struct wined3d_rendertarget_view *object;
763 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
764 if (!object)
766 ERR("Failed to allocate memory\n");
767 return E_OUTOFMEMORY;
770 object->vtbl = &wined3d_rendertarget_view_vtbl;
771 object->refcount = 1;
772 IWineD3DResource_AddRef(resource);
773 object->resource = resource;
774 object->parent = parent;
776 *rendertarget_view = (IWineD3DRendertargetView *)object;
778 return WINED3D_OK;
781 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
782 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
783 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
786 IWineD3DTextureImpl *object;
787 HRESULT hr;
789 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
790 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
791 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
793 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
794 if (!object)
796 ERR("Out of memory\n");
797 *ppTexture = NULL;
798 return WINED3DERR_OUTOFVIDEOMEMORY;
801 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
802 if (FAILED(hr))
804 WARN("Failed to initialize texture, returning %#x\n", hr);
805 HeapFree(GetProcessHeap(), 0, object);
806 *ppTexture = NULL;
807 return hr;
810 *ppTexture = (IWineD3DTexture *)object;
812 TRACE("(%p) : Created texture %p\n", This, object);
814 return WINED3D_OK;
817 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
818 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
819 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
822 IWineD3DVolumeTextureImpl *object;
823 HRESULT hr;
825 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
826 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
829 if (!object)
831 ERR("Out of memory\n");
832 *ppVolumeTexture = NULL;
833 return WINED3DERR_OUTOFVIDEOMEMORY;
836 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
837 if (FAILED(hr))
839 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
840 HeapFree(GetProcessHeap(), 0, object);
841 *ppVolumeTexture = NULL;
842 return hr;
845 TRACE("(%p) : Created volume texture %p.\n", This, object);
846 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
848 return WINED3D_OK;
851 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
852 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
853 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 IWineD3DVolumeImpl *object;
857 HRESULT hr;
859 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
860 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
862 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
863 if (!object)
865 ERR("Out of memory\n");
866 *ppVolume = NULL;
867 return WINED3DERR_OUTOFVIDEOMEMORY;
870 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
871 if (FAILED(hr))
873 WARN("Failed to initialize volume, returning %#x.\n", hr);
874 HeapFree(GetProcessHeap(), 0, object);
875 return hr;
878 TRACE("(%p) : Created volume %p.\n", This, object);
879 *ppVolume = (IWineD3DVolume *)object;
881 return WINED3D_OK;
884 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
885 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
886 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
889 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
890 HRESULT hr;
892 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
893 if (!object)
895 ERR("Out of memory\n");
896 *ppCubeTexture = NULL;
897 return WINED3DERR_OUTOFVIDEOMEMORY;
900 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
901 if (FAILED(hr))
903 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
904 HeapFree(GetProcessHeap(), 0, object);
905 *ppCubeTexture = NULL;
906 return hr;
909 TRACE("(%p) : Created Cube Texture %p\n", This, object);
910 *ppCubeTexture = (IWineD3DCubeTexture *)object;
912 return WINED3D_OK;
915 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
916 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
919 IWineD3DQueryImpl *object;
920 HRESULT hr;
922 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
925 if (!object)
927 ERR("Failed to allocate query memory.\n");
928 return E_OUTOFMEMORY;
931 hr = query_init(object, This, type, parent);
932 if (FAILED(hr))
934 WARN("Failed to initialize query, hr %#x.\n", hr);
935 HeapFree(GetProcessHeap(), 0, object);
936 return hr;
939 TRACE("Created query %p.\n", object);
940 *query = (IWineD3DQuery *)object;
942 return WINED3D_OK;
945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
946 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
947 IUnknown *parent, WINED3DSURFTYPE surface_type)
949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
950 IWineD3DSwapChainImpl *object;
951 HRESULT hr;
953 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
954 iface, present_parameters, swapchain, parent, surface_type);
956 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
957 if (!object)
959 ERR("Failed to allocate swapchain memory.\n");
960 return E_OUTOFMEMORY;
963 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
964 if (FAILED(hr))
966 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
967 HeapFree(GetProcessHeap(), 0, object);
968 return hr;
971 TRACE("Created swapchain %p.\n", object);
972 *swapchain = (IWineD3DSwapChain *)object;
974 return WINED3D_OK;
977 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
978 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
980 TRACE("(%p)\n", This);
982 return This->NumberOfSwapChains;
985 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
987 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
989 if(iSwapChain < This->NumberOfSwapChains) {
990 *pSwapChain = This->swapchains[iSwapChain];
991 IWineD3DSwapChain_AddRef(*pSwapChain);
992 TRACE("(%p) returning %p\n", This, *pSwapChain);
993 return WINED3D_OK;
994 } else {
995 TRACE("Swapchain out of range\n");
996 *pSwapChain = NULL;
997 return WINED3DERR_INVALIDCALL;
1001 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1002 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1003 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DVertexDeclarationImpl *object = NULL;
1007 HRESULT hr;
1009 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1010 iface, declaration, parent, elements, element_count);
1012 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1013 if(!object)
1015 ERR("Failed to allocate vertex declaration memory.\n");
1016 return E_OUTOFMEMORY;
1019 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1020 if (FAILED(hr))
1022 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1023 HeapFree(GetProcessHeap(), 0, object);
1024 return hr;
1027 TRACE("Created vertex declaration %p.\n", object);
1028 *declaration = (IWineD3DVertexDeclaration *)object;
1030 return WINED3D_OK;
1033 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1034 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1036 unsigned int idx, idx2;
1037 unsigned int offset;
1038 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1039 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1040 BOOL has_blend_idx = has_blend &&
1041 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1042 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1043 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1044 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1045 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1046 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1047 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1049 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1050 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1051 WINED3DVERTEXELEMENT *elements = NULL;
1053 unsigned int size;
1054 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1055 if (has_blend_idx) num_blends--;
1057 /* Compute declaration size */
1058 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1059 has_psize + has_diffuse + has_specular + num_textures;
1061 /* convert the declaration */
1062 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1063 if (!elements) return ~0U;
1065 idx = 0;
1066 if (has_pos) {
1067 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1068 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1069 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1071 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1072 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1073 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1075 else {
1076 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1077 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1079 elements[idx].usage_idx = 0;
1080 idx++;
1082 if (has_blend && (num_blends > 0)) {
1083 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1084 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1085 else {
1086 switch(num_blends) {
1087 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1088 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1089 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1090 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1091 default:
1092 ERR("Unexpected amount of blend values: %u\n", num_blends);
1095 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1096 elements[idx].usage_idx = 0;
1097 idx++;
1099 if (has_blend_idx) {
1100 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1101 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1102 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1103 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1104 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1105 else
1106 elements[idx].format = WINED3DFMT_R32_FLOAT;
1107 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1108 elements[idx].usage_idx = 0;
1109 idx++;
1111 if (has_normal) {
1112 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1113 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1114 elements[idx].usage_idx = 0;
1115 idx++;
1117 if (has_psize) {
1118 elements[idx].format = WINED3DFMT_R32_FLOAT;
1119 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1120 elements[idx].usage_idx = 0;
1121 idx++;
1123 if (has_diffuse) {
1124 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1125 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1126 elements[idx].usage_idx = 0;
1127 idx++;
1129 if (has_specular) {
1130 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1131 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1132 elements[idx].usage_idx = 1;
1133 idx++;
1135 for (idx2 = 0; idx2 < num_textures; idx2++) {
1136 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1137 switch (numcoords) {
1138 case WINED3DFVF_TEXTUREFORMAT1:
1139 elements[idx].format = WINED3DFMT_R32_FLOAT;
1140 break;
1141 case WINED3DFVF_TEXTUREFORMAT2:
1142 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1143 break;
1144 case WINED3DFVF_TEXTUREFORMAT3:
1145 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1146 break;
1147 case WINED3DFVF_TEXTUREFORMAT4:
1148 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1149 break;
1151 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1152 elements[idx].usage_idx = idx2;
1153 idx++;
1156 /* Now compute offsets, and initialize the rest of the fields */
1157 for (idx = 0, offset = 0; idx < size; ++idx)
1159 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1160 elements[idx].input_slot = 0;
1161 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1162 elements[idx].offset = offset;
1163 offset += format_desc->component_count * format_desc->component_size;
1166 *ppVertexElements = elements;
1167 return size;
1170 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1171 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1172 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1175 WINED3DVERTEXELEMENT *elements;
1176 unsigned int size;
1177 DWORD hr;
1179 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1181 size = ConvertFvfToDeclaration(This, fvf, &elements);
1182 if (size == ~0U) return E_OUTOFMEMORY;
1184 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1185 HeapFree(GetProcessHeap(), 0, elements);
1186 return hr;
1189 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1190 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1191 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1192 const struct wined3d_parent_ops *parent_ops)
1194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1195 IWineD3DVertexShaderImpl *object;
1196 HRESULT hr;
1198 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1199 if (!object)
1201 ERR("Failed to allocate shader memory.\n");
1202 return E_OUTOFMEMORY;
1205 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1206 if (FAILED(hr))
1208 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1209 HeapFree(GetProcessHeap(), 0, object);
1210 return hr;
1213 TRACE("Created vertex shader %p.\n", object);
1214 *ppVertexShader = (IWineD3DVertexShader *)object;
1216 return WINED3D_OK;
1219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1220 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1221 IWineD3DGeometryShader **shader, IUnknown *parent,
1222 const struct wined3d_parent_ops *parent_ops)
1224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1225 struct wined3d_geometryshader *object;
1226 HRESULT hr;
1228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1229 if (!object)
1231 ERR("Failed to allocate shader memory.\n");
1232 return E_OUTOFMEMORY;
1235 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1236 if (FAILED(hr))
1238 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1239 HeapFree(GetProcessHeap(), 0, object);
1240 return hr;
1243 TRACE("Created geometry shader %p.\n", object);
1244 *shader = (IWineD3DGeometryShader *)object;
1246 return WINED3D_OK;
1249 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1250 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1251 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1252 const struct wined3d_parent_ops *parent_ops)
1254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1255 IWineD3DPixelShaderImpl *object;
1256 HRESULT hr;
1258 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1259 if (!object)
1261 ERR("Failed to allocate shader memory.\n");
1262 return E_OUTOFMEMORY;
1265 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1266 if (FAILED(hr))
1268 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1269 HeapFree(GetProcessHeap(), 0, object);
1270 return hr;
1273 TRACE("Created pixel shader %p.\n", object);
1274 *ppPixelShader = (IWineD3DPixelShader *)object;
1276 return WINED3D_OK;
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1280 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1283 IWineD3DPaletteImpl *object;
1284 HRESULT hr;
1285 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1287 /* Create the new object */
1288 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1289 if(!object) {
1290 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1291 return E_OUTOFMEMORY;
1294 object->lpVtbl = &IWineD3DPalette_Vtbl;
1295 object->ref = 1;
1296 object->Flags = Flags;
1297 object->parent = Parent;
1298 object->device = This;
1299 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1300 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1302 if(!object->hpal) {
1303 HeapFree( GetProcessHeap(), 0, object);
1304 return E_OUTOFMEMORY;
1307 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1308 if(FAILED(hr)) {
1309 IWineD3DPalette_Release((IWineD3DPalette *) object);
1310 return hr;
1313 *Palette = (IWineD3DPalette *) object;
1315 return WINED3D_OK;
1318 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1319 HBITMAP hbm;
1320 BITMAP bm;
1321 HRESULT hr;
1322 HDC dcb = NULL, dcs = NULL;
1323 WINEDDCOLORKEY colorkey;
1325 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1326 if(hbm)
1328 GetObjectA(hbm, sizeof(BITMAP), &bm);
1329 dcb = CreateCompatibleDC(NULL);
1330 if(!dcb) goto out;
1331 SelectObject(dcb, hbm);
1333 else
1335 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1336 * couldn't be loaded
1338 memset(&bm, 0, sizeof(bm));
1339 bm.bmWidth = 32;
1340 bm.bmHeight = 32;
1343 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1344 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1345 NULL, &wined3d_null_parent_ops);
1346 if(FAILED(hr)) {
1347 ERR("Wine logo requested, but failed to create surface\n");
1348 goto out;
1351 if(dcb) {
1352 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1353 if(FAILED(hr)) goto out;
1354 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1355 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1357 colorkey.dwColorSpaceLowValue = 0;
1358 colorkey.dwColorSpaceHighValue = 0;
1359 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1360 } else {
1361 /* Fill the surface with a white color to show that wined3d is there */
1362 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1365 out:
1366 if (dcb) DeleteDC(dcb);
1367 if (hbm) DeleteObject(hbm);
1370 /* Context activation is done by the caller. */
1371 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1373 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1374 unsigned int i;
1375 /* Under DirectX you can have texture stage operations even if no texture is
1376 bound, whereas opengl will only do texture operations when a valid texture is
1377 bound. We emulate this by creating dummy textures and binding them to each
1378 texture stage, but disable all stages by default. Hence if a stage is enabled
1379 then the default texture will kick in until replaced by a SetTexture call */
1380 ENTER_GL();
1382 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1384 /* The dummy texture does not have client storage backing */
1385 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1386 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1389 for (i = 0; i < gl_info->limits.textures; ++i)
1391 GLubyte white = 255;
1393 /* Make appropriate texture active */
1394 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1395 checkGLcall("glActiveTextureARB");
1397 /* Generate an opengl texture name */
1398 glGenTextures(1, &This->dummyTextureName[i]);
1399 checkGLcall("glGenTextures");
1400 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1402 /* Generate a dummy 2d texture (not using 1d because they cause many
1403 * DRI drivers fall back to sw) */
1404 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1405 checkGLcall("glBindTexture");
1407 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1408 checkGLcall("glTexImage2D");
1411 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1413 /* Reenable because if supported it is enabled by default */
1414 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1415 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1418 LEAVE_GL();
1421 /* Context activation is done by the caller. */
1422 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1424 ENTER_GL();
1425 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1426 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1427 LEAVE_GL();
1429 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1432 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1433 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1436 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1437 IWineD3DSwapChainImpl *swapchain = NULL;
1438 struct wined3d_context *context;
1439 HRESULT hr;
1440 DWORD state;
1441 unsigned int i;
1443 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1445 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1446 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1448 if (!pPresentationParameters->Windowed)
1450 This->focus_window = This->createParms.hFocusWindow;
1451 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1452 if (!wined3d_register_window(This->focus_window, This))
1454 ERR("Failed to register window %p.\n", This->focus_window);
1455 return E_FAIL;
1459 TRACE("(%p) : Creating stateblock\n", This);
1460 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1461 hr = IWineD3DDevice_CreateStateBlock(iface,
1462 WINED3DSBT_INIT,
1463 (IWineD3DStateBlock **)&This->stateBlock,
1464 NULL);
1465 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1466 WARN("Failed to create stateblock\n");
1467 goto err_out;
1469 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1470 This->updateStateBlock = This->stateBlock;
1471 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1473 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1474 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1475 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1476 sizeof(GLenum) * gl_info->limits.buffers);
1478 This->NumberOfPalettes = 1;
1479 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1480 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1481 ERR("Out of memory!\n");
1482 hr = E_OUTOFMEMORY;
1483 goto err_out;
1485 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1486 if(!This->palettes[0]) {
1487 ERR("Out of memory!\n");
1488 hr = E_OUTOFMEMORY;
1489 goto err_out;
1491 for (i = 0; i < 256; ++i) {
1492 This->palettes[0][i].peRed = 0xFF;
1493 This->palettes[0][i].peGreen = 0xFF;
1494 This->palettes[0][i].peBlue = 0xFF;
1495 This->palettes[0][i].peFlags = 0xFF;
1497 This->currentPalette = 0;
1499 /* Initialize the texture unit mapping to a 1:1 mapping */
1500 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1502 if (state < gl_info->limits.fragment_samplers)
1504 This->texUnitMap[state] = state;
1505 This->rev_tex_unit_map[state] = state;
1506 } else {
1507 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1508 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1512 if (This->focus_window) SetFocus(This->focus_window);
1514 /* Setup the implicit swapchain. This also initializes a context. */
1515 TRACE("Creating implicit swapchain\n");
1516 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1517 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1518 if (FAILED(hr))
1520 WARN("Failed to create implicit swapchain\n");
1521 goto err_out;
1524 This->NumberOfSwapChains = 1;
1525 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1526 if(!This->swapchains) {
1527 ERR("Out of memory!\n");
1528 goto err_out;
1530 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1532 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1533 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1534 This->render_targets[0] = swapchain->backBuffer[0];
1536 else {
1537 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1538 This->render_targets[0] = swapchain->frontBuffer;
1540 IWineD3DSurface_AddRef(This->render_targets[0]);
1542 /* Depth Stencil support */
1543 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1544 if (NULL != This->stencilBufferTarget) {
1545 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1548 hr = This->shader_backend->shader_alloc_private(iface);
1549 if(FAILED(hr)) {
1550 TRACE("Shader private data couldn't be allocated\n");
1551 goto err_out;
1553 hr = This->frag_pipe->alloc_private(iface);
1554 if(FAILED(hr)) {
1555 TRACE("Fragment pipeline private data couldn't be allocated\n");
1556 goto err_out;
1558 hr = This->blitter->alloc_private(iface);
1559 if(FAILED(hr)) {
1560 TRACE("Blitter private data couldn't be allocated\n");
1561 goto err_out;
1564 /* Set up some starting GL setup */
1566 /* Setup all the devices defaults */
1567 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1569 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1571 create_dummy_textures(This);
1573 ENTER_GL();
1575 /* Initialize the current view state */
1576 This->view_ident = 1;
1577 This->contexts[0]->last_was_rhw = 0;
1578 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1579 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1581 switch(wined3d_settings.offscreen_rendering_mode) {
1582 case ORM_FBO:
1583 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1584 break;
1586 case ORM_PBUFFER:
1587 This->offscreenBuffer = GL_BACK;
1588 break;
1590 case ORM_BACKBUFFER:
1592 if (context_get_current()->aux_buffers > 0)
1594 TRACE("Using auxilliary buffer for offscreen rendering\n");
1595 This->offscreenBuffer = GL_AUX0;
1596 } else {
1597 TRACE("Using back buffer for offscreen rendering\n");
1598 This->offscreenBuffer = GL_BACK;
1603 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1604 LEAVE_GL();
1606 context_release(context);
1608 /* Clear the screen */
1609 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1610 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1611 0x00, 1.0f, 0);
1613 This->d3d_initialized = TRUE;
1615 if(wined3d_settings.logo) {
1616 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1618 This->highest_dirty_ps_const = 0;
1619 This->highest_dirty_vs_const = 0;
1620 return WINED3D_OK;
1622 err_out:
1623 HeapFree(GetProcessHeap(), 0, This->render_targets);
1624 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1625 HeapFree(GetProcessHeap(), 0, This->swapchains);
1626 This->NumberOfSwapChains = 0;
1627 if(This->palettes) {
1628 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1629 HeapFree(GetProcessHeap(), 0, This->palettes);
1631 This->NumberOfPalettes = 0;
1632 if(swapchain) {
1633 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1635 if(This->stateBlock) {
1636 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1637 This->stateBlock = NULL;
1639 if (This->blit_priv) {
1640 This->blitter->free_private(iface);
1642 if (This->fragment_priv) {
1643 This->frag_pipe->free_private(iface);
1645 if (This->shader_priv) {
1646 This->shader_backend->shader_free_private(iface);
1648 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1649 return hr;
1652 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1653 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1656 IWineD3DSwapChainImpl *swapchain = NULL;
1657 HRESULT hr;
1659 /* Setup the implicit swapchain */
1660 TRACE("Creating implicit swapchain\n");
1661 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1662 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1663 if (FAILED(hr))
1665 WARN("Failed to create implicit swapchain\n");
1666 goto err_out;
1669 This->NumberOfSwapChains = 1;
1670 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1671 if(!This->swapchains) {
1672 ERR("Out of memory!\n");
1673 goto err_out;
1675 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1676 return WINED3D_OK;
1678 err_out:
1679 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1680 return hr;
1683 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1685 IWineD3DResource_UnLoad(resource);
1686 IWineD3DResource_Release(resource);
1687 return WINED3D_OK;
1690 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1691 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1694 const struct wined3d_gl_info *gl_info;
1695 struct wined3d_context *context;
1696 int sampler;
1697 UINT i;
1698 TRACE("(%p)\n", This);
1700 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1702 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1703 * it was created. Thus make sure a context is active for the glDelete* calls
1705 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1706 gl_info = context->gl_info;
1708 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1710 /* Unload resources */
1711 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1713 TRACE("Deleting high order patches\n");
1714 for(i = 0; i < PATCHMAP_SIZE; i++) {
1715 struct list *e1, *e2;
1716 struct WineD3DRectPatch *patch;
1717 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1718 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1719 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1723 /* Delete the pbuffer context if there is any */
1724 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1726 /* Delete the mouse cursor texture */
1727 if(This->cursorTexture) {
1728 ENTER_GL();
1729 glDeleteTextures(1, &This->cursorTexture);
1730 LEAVE_GL();
1731 This->cursorTexture = 0;
1734 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1735 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1737 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1738 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1741 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1742 * private data, it might contain opengl pointers
1744 if(This->depth_blt_texture) {
1745 ENTER_GL();
1746 glDeleteTextures(1, &This->depth_blt_texture);
1747 LEAVE_GL();
1748 This->depth_blt_texture = 0;
1750 if (This->depth_blt_rb) {
1751 ENTER_GL();
1752 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1753 LEAVE_GL();
1754 This->depth_blt_rb = 0;
1755 This->depth_blt_rb_w = 0;
1756 This->depth_blt_rb_h = 0;
1759 /* Release the update stateblock */
1760 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1761 if(This->updateStateBlock != This->stateBlock)
1762 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1764 This->updateStateBlock = NULL;
1766 { /* because were not doing proper internal refcounts releasing the primary state block
1767 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1768 to set this->stateBlock = NULL; first */
1769 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1770 This->stateBlock = NULL;
1772 /* Release the stateblock */
1773 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1774 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1778 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1779 This->blitter->free_private(iface);
1780 This->frag_pipe->free_private(iface);
1781 This->shader_backend->shader_free_private(iface);
1783 /* Release the buffers (with sanity checks)*/
1784 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1785 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1786 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1787 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1789 This->stencilBufferTarget = NULL;
1791 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1792 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1793 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1795 TRACE("Setting rendertarget to NULL\n");
1796 This->render_targets[0] = NULL;
1798 if (This->auto_depth_stencil_buffer) {
1799 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1801 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1803 This->auto_depth_stencil_buffer = NULL;
1806 context_release(context);
1808 for(i=0; i < This->NumberOfSwapChains; i++) {
1809 TRACE("Releasing the implicit swapchain %d\n", i);
1810 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1811 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1815 HeapFree(GetProcessHeap(), 0, This->swapchains);
1816 This->swapchains = NULL;
1817 This->NumberOfSwapChains = 0;
1819 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1820 HeapFree(GetProcessHeap(), 0, This->palettes);
1821 This->palettes = NULL;
1822 This->NumberOfPalettes = 0;
1824 HeapFree(GetProcessHeap(), 0, This->render_targets);
1825 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1826 This->render_targets = NULL;
1827 This->draw_buffers = NULL;
1829 This->d3d_initialized = FALSE;
1831 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1833 return WINED3D_OK;
1836 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1838 unsigned int i;
1840 for(i=0; i < This->NumberOfSwapChains; i++) {
1841 TRACE("Releasing the implicit swapchain %d\n", i);
1842 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1843 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1847 HeapFree(GetProcessHeap(), 0, This->swapchains);
1848 This->swapchains = NULL;
1849 This->NumberOfSwapChains = 0;
1850 return WINED3D_OK;
1853 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1854 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1855 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1857 * There is no way to deactivate thread safety once it is enabled.
1859 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1862 /*For now just store the flag(needed in case of ddraw) */
1863 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1866 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1867 const WINED3DDISPLAYMODE* pMode) {
1868 DEVMODEW devmode;
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1870 LONG ret;
1871 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1872 RECT clip_rc;
1874 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1876 /* Resize the screen even without a window:
1877 * The app could have unset it with SetCooperativeLevel, but not called
1878 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1879 * but we don't have any hwnd
1882 memset(&devmode, 0, sizeof(devmode));
1883 devmode.dmSize = sizeof(devmode);
1884 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1885 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1886 devmode.dmPelsWidth = pMode->Width;
1887 devmode.dmPelsHeight = pMode->Height;
1889 devmode.dmDisplayFrequency = pMode->RefreshRate;
1890 if (pMode->RefreshRate != 0) {
1891 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1894 /* Only change the mode if necessary */
1895 if( (This->ddraw_width == pMode->Width) &&
1896 (This->ddraw_height == pMode->Height) &&
1897 (This->ddraw_format == pMode->Format) &&
1898 (pMode->RefreshRate == 0) ) {
1899 return WINED3D_OK;
1902 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1903 if (ret != DISP_CHANGE_SUCCESSFUL) {
1904 if(devmode.dmDisplayFrequency != 0) {
1905 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1906 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1907 devmode.dmDisplayFrequency = 0;
1908 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1910 if(ret != DISP_CHANGE_SUCCESSFUL) {
1911 return WINED3DERR_NOTAVAILABLE;
1915 /* Store the new values */
1916 This->ddraw_width = pMode->Width;
1917 This->ddraw_height = pMode->Height;
1918 This->ddraw_format = pMode->Format;
1920 /* And finally clip mouse to our screen */
1921 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1922 ClipCursor(&clip_rc);
1924 return WINED3D_OK;
1927 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1929 *ppD3D = This->wined3d;
1930 TRACE("Returning %p.\n", *ppD3D);
1931 IWineD3D_AddRef(*ppD3D);
1932 return WINED3D_OK;
1935 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1938 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1939 (This->adapter->TextureRam/(1024*1024)),
1940 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1941 /* return simulated texture memory left */
1942 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1945 /*****
1946 * Get / Set Stream Source
1947 *****/
1948 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1949 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1952 IWineD3DBuffer *oldSrc;
1954 if (StreamNumber >= MAX_STREAMS) {
1955 WARN("Stream out of range %d\n", StreamNumber);
1956 return WINED3DERR_INVALIDCALL;
1957 } else if(OffsetInBytes & 0x3) {
1958 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1959 return WINED3DERR_INVALIDCALL;
1962 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1963 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1965 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1967 if(oldSrc == pStreamData &&
1968 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1969 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1970 TRACE("Application is setting the old values over, nothing to do\n");
1971 return WINED3D_OK;
1974 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1975 if (pStreamData) {
1976 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1977 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1980 /* Handle recording of state blocks */
1981 if (This->isRecordingState) {
1982 TRACE("Recording... not performing anything\n");
1983 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1984 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1985 return WINED3D_OK;
1988 if (pStreamData != NULL) {
1989 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1990 IWineD3DBuffer_AddRef(pStreamData);
1992 if (oldSrc != NULL) {
1993 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1994 IWineD3DBuffer_Release(oldSrc);
1997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1999 return WINED3D_OK;
2002 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2003 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2007 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2008 This->stateBlock->streamSource[StreamNumber],
2009 This->stateBlock->streamOffset[StreamNumber],
2010 This->stateBlock->streamStride[StreamNumber]);
2012 if (StreamNumber >= MAX_STREAMS) {
2013 WARN("Stream out of range %d\n", StreamNumber);
2014 return WINED3DERR_INVALIDCALL;
2016 *pStream = This->stateBlock->streamSource[StreamNumber];
2017 *pStride = This->stateBlock->streamStride[StreamNumber];
2018 if (pOffset) {
2019 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2022 if (*pStream != NULL) {
2023 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2025 return WINED3D_OK;
2028 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2030 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2031 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2033 /* Verify input at least in d3d9 this is invalid*/
2034 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2035 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2036 return WINED3DERR_INVALIDCALL;
2038 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2039 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2040 return WINED3DERR_INVALIDCALL;
2042 if( Divider == 0 ){
2043 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2044 return WINED3DERR_INVALIDCALL;
2047 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2048 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2050 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2051 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2053 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2054 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2058 return WINED3D_OK;
2061 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2064 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2065 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2067 TRACE("(%p) : returning %d\n", This, *Divider);
2069 return WINED3D_OK;
2072 /*****
2073 * Get / Set & Multiply Transform
2074 *****/
2075 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2078 /* Most of this routine, comments included copied from ddraw tree initially: */
2079 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2081 /* Handle recording of state blocks */
2082 if (This->isRecordingState) {
2083 TRACE("Recording... not performing anything\n");
2084 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2085 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2086 return WINED3D_OK;
2090 * If the new matrix is the same as the current one,
2091 * we cut off any further processing. this seems to be a reasonable
2092 * optimization because as was noticed, some apps (warcraft3 for example)
2093 * tend towards setting the same matrix repeatedly for some reason.
2095 * From here on we assume that the new matrix is different, wherever it matters.
2097 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2098 TRACE("The app is setting the same matrix over again\n");
2099 return WINED3D_OK;
2100 } else {
2101 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2105 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2106 where ViewMat = Camera space, WorldMat = world space.
2108 In OpenGL, camera and world space is combined into GL_MODELVIEW
2109 matrix. The Projection matrix stay projection matrix.
2112 /* Capture the times we can just ignore the change for now */
2113 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2114 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2115 /* Handled by the state manager */
2118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2119 return WINED3D_OK;
2122 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2124 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2125 *pMatrix = This->stateBlock->transforms[State];
2126 return WINED3D_OK;
2129 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2130 const WINED3DMATRIX *mat = NULL;
2131 WINED3DMATRIX temp;
2133 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2134 * below means it will be recorded in a state block change, but it
2135 * works regardless where it is recorded.
2136 * If this is found to be wrong, change to StateBlock.
2138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2139 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2141 if (State <= HIGHEST_TRANSFORMSTATE)
2143 mat = &This->updateStateBlock->transforms[State];
2144 } else {
2145 FIXME("Unhandled transform state!!\n");
2148 multiply_matrix(&temp, mat, pMatrix);
2150 /* Apply change via set transform - will reapply to eg. lights this way */
2151 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2154 /*****
2155 * Get / Set Light
2156 *****/
2157 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2158 you can reference any indexes you want as long as that number max are enabled at any
2159 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2160 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2161 but when recording, just build a chain pretty much of commands to be replayed. */
2163 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2164 float rho;
2165 struct wined3d_light_info *object = NULL;
2166 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2167 struct list *e;
2169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2170 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2172 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2173 * the gl driver.
2175 if(!pLight) {
2176 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2177 return WINED3DERR_INVALIDCALL;
2180 switch(pLight->Type) {
2181 case WINED3DLIGHT_POINT:
2182 case WINED3DLIGHT_SPOT:
2183 case WINED3DLIGHT_PARALLELPOINT:
2184 case WINED3DLIGHT_GLSPOT:
2185 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2186 * most wanted
2188 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2190 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2191 return WINED3DERR_INVALIDCALL;
2193 break;
2195 case WINED3DLIGHT_DIRECTIONAL:
2196 /* Ignores attenuation */
2197 break;
2199 default:
2200 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2201 return WINED3DERR_INVALIDCALL;
2204 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2206 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2207 if(object->OriginalIndex == Index) break;
2208 object = NULL;
2211 if(!object) {
2212 TRACE("Adding new light\n");
2213 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2214 if(!object) {
2215 ERR("Out of memory error when allocating a light\n");
2216 return E_OUTOFMEMORY;
2218 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2219 object->glIndex = -1;
2220 object->OriginalIndex = Index;
2223 /* Initialize the object */
2224 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,
2225 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2226 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2227 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2228 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2229 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2230 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2232 /* Save away the information */
2233 object->OriginalParms = *pLight;
2235 switch (pLight->Type) {
2236 case WINED3DLIGHT_POINT:
2237 /* Position */
2238 object->lightPosn[0] = pLight->Position.x;
2239 object->lightPosn[1] = pLight->Position.y;
2240 object->lightPosn[2] = pLight->Position.z;
2241 object->lightPosn[3] = 1.0f;
2242 object->cutoff = 180.0f;
2243 /* FIXME: Range */
2244 break;
2246 case WINED3DLIGHT_DIRECTIONAL:
2247 /* Direction */
2248 object->lightPosn[0] = -pLight->Direction.x;
2249 object->lightPosn[1] = -pLight->Direction.y;
2250 object->lightPosn[2] = -pLight->Direction.z;
2251 object->lightPosn[3] = 0.0f;
2252 object->exponent = 0.0f;
2253 object->cutoff = 180.0f;
2254 break;
2256 case WINED3DLIGHT_SPOT:
2257 /* Position */
2258 object->lightPosn[0] = pLight->Position.x;
2259 object->lightPosn[1] = pLight->Position.y;
2260 object->lightPosn[2] = pLight->Position.z;
2261 object->lightPosn[3] = 1.0f;
2263 /* Direction */
2264 object->lightDirn[0] = pLight->Direction.x;
2265 object->lightDirn[1] = pLight->Direction.y;
2266 object->lightDirn[2] = pLight->Direction.z;
2267 object->lightDirn[3] = 1.0f;
2270 * opengl-ish and d3d-ish spot lights use too different models for the
2271 * light "intensity" as a function of the angle towards the main light direction,
2272 * so we only can approximate very roughly.
2273 * however spot lights are rather rarely used in games (if ever used at all).
2274 * furthermore if still used, probably nobody pays attention to such details.
2276 if (pLight->Falloff == 0) {
2277 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2278 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2279 * will always be 1.0 for both of them, and we don't have to care for the
2280 * rest of the rather complex calculation
2282 object->exponent = 0.0f;
2283 } else {
2284 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2285 if (rho < 0.0001f) rho = 0.0001f;
2286 object->exponent = -0.3f/logf(cosf(rho/2));
2288 if (object->exponent > 128.0f)
2290 object->exponent = 128.0f;
2292 object->cutoff = pLight->Phi*90/M_PI;
2294 /* FIXME: Range */
2295 break;
2297 default:
2298 FIXME("Unrecognized light type %d\n", pLight->Type);
2301 /* Update the live definitions if the light is currently assigned a glIndex */
2302 if (object->glIndex != -1 && !This->isRecordingState) {
2303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2305 return WINED3D_OK;
2308 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2310 struct wined3d_light_info *lightInfo = NULL;
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2312 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2313 struct list *e;
2314 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2316 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2318 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2319 if(lightInfo->OriginalIndex == Index) break;
2320 lightInfo = NULL;
2323 if (lightInfo == NULL) {
2324 TRACE("Light information requested but light not defined\n");
2325 return WINED3DERR_INVALIDCALL;
2328 *pLight = lightInfo->OriginalParms;
2329 return WINED3D_OK;
2332 /*****
2333 * Get / Set Light Enable
2334 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2335 *****/
2336 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2338 struct wined3d_light_info *lightInfo = NULL;
2339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2340 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2341 struct list *e;
2342 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2344 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2346 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2347 if(lightInfo->OriginalIndex == Index) break;
2348 lightInfo = NULL;
2350 TRACE("Found light: %p\n", lightInfo);
2352 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2353 if (lightInfo == NULL) {
2355 TRACE("Light enabled requested but light not defined, so defining one!\n");
2356 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2358 /* Search for it again! Should be fairly quick as near head of list */
2359 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2361 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2362 if(lightInfo->OriginalIndex == Index) break;
2363 lightInfo = NULL;
2365 if (lightInfo == NULL) {
2366 FIXME("Adding default lights has failed dismally\n");
2367 return WINED3DERR_INVALIDCALL;
2371 if(!Enable) {
2372 if(lightInfo->glIndex != -1) {
2373 if(!This->isRecordingState) {
2374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2377 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2378 lightInfo->glIndex = -1;
2379 } else {
2380 TRACE("Light already disabled, nothing to do\n");
2382 lightInfo->enabled = FALSE;
2383 } else {
2384 lightInfo->enabled = TRUE;
2385 if (lightInfo->glIndex != -1) {
2386 /* nop */
2387 TRACE("Nothing to do as light was enabled\n");
2388 } else {
2389 int i;
2390 /* Find a free gl light */
2391 for(i = 0; i < This->maxConcurrentLights; i++) {
2392 if(This->updateStateBlock->activeLights[i] == NULL) {
2393 This->updateStateBlock->activeLights[i] = lightInfo;
2394 lightInfo->glIndex = i;
2395 break;
2398 if(lightInfo->glIndex == -1) {
2399 /* Our tests show that Windows returns D3D_OK in this situation, even with
2400 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2401 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2402 * as well for those lights.
2404 * TODO: Test how this affects rendering
2406 WARN("Too many concurrently active lights\n");
2407 return WINED3D_OK;
2410 /* i == lightInfo->glIndex */
2411 if(!This->isRecordingState) {
2412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2417 return WINED3D_OK;
2420 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2422 struct wined3d_light_info *lightInfo = NULL;
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2424 struct list *e;
2425 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2426 TRACE("(%p) : for idx(%d)\n", This, Index);
2428 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2430 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2431 if(lightInfo->OriginalIndex == Index) break;
2432 lightInfo = NULL;
2435 if (lightInfo == NULL) {
2436 TRACE("Light enabled state requested but light not defined\n");
2437 return WINED3DERR_INVALIDCALL;
2439 /* true is 128 according to SetLightEnable */
2440 *pEnable = lightInfo->enabled ? 128 : 0;
2441 return WINED3D_OK;
2444 /*****
2445 * Get / Set Clip Planes
2446 *****/
2447 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2449 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2451 /* Validate Index */
2452 if (Index >= This->adapter->gl_info.limits.clipplanes)
2454 TRACE("Application has requested clipplane this device doesn't support\n");
2455 return WINED3DERR_INVALIDCALL;
2458 This->updateStateBlock->changed.clipplane |= 1 << Index;
2460 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2461 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2462 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2463 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2464 TRACE("Application is setting old values over, nothing to do\n");
2465 return WINED3D_OK;
2468 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2469 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2470 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2471 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2473 /* Handle recording of state blocks */
2474 if (This->isRecordingState) {
2475 TRACE("Recording... not performing anything\n");
2476 return WINED3D_OK;
2479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2481 return WINED3D_OK;
2484 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2486 TRACE("(%p) : for idx %d\n", This, Index);
2488 /* Validate Index */
2489 if (Index >= This->adapter->gl_info.limits.clipplanes)
2491 TRACE("Application has requested clipplane this device doesn't support\n");
2492 return WINED3DERR_INVALIDCALL;
2495 pPlane[0] = This->stateBlock->clipplane[Index][0];
2496 pPlane[1] = This->stateBlock->clipplane[Index][1];
2497 pPlane[2] = This->stateBlock->clipplane[Index][2];
2498 pPlane[3] = This->stateBlock->clipplane[Index][3];
2499 return WINED3D_OK;
2502 /*****
2503 * Get / Set Clip Plane Status
2504 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2505 *****/
2506 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 FIXME("(%p) : stub\n", This);
2509 if (NULL == pClipStatus) {
2510 return WINED3DERR_INVALIDCALL;
2512 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2513 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2514 return WINED3D_OK;
2517 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2519 FIXME("(%p) : stub\n", This);
2520 if (NULL == pClipStatus) {
2521 return WINED3DERR_INVALIDCALL;
2523 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2524 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2525 return WINED3D_OK;
2528 /*****
2529 * Get / Set Material
2530 *****/
2531 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2534 This->updateStateBlock->changed.material = TRUE;
2535 This->updateStateBlock->material = *pMaterial;
2537 /* Handle recording of state blocks */
2538 if (This->isRecordingState) {
2539 TRACE("Recording... not performing anything\n");
2540 return WINED3D_OK;
2543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2544 return WINED3D_OK;
2547 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 *pMaterial = This->updateStateBlock->material;
2550 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2551 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2552 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2553 pMaterial->Ambient.b, pMaterial->Ambient.a);
2554 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2555 pMaterial->Specular.b, pMaterial->Specular.a);
2556 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2557 pMaterial->Emissive.b, pMaterial->Emissive.a);
2558 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2560 return WINED3D_OK;
2563 /*****
2564 * Get / Set Indices
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2567 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 IWineD3DBuffer *oldIdxs;
2572 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2573 oldIdxs = This->updateStateBlock->pIndexData;
2575 This->updateStateBlock->changed.indices = TRUE;
2576 This->updateStateBlock->pIndexData = pIndexData;
2577 This->updateStateBlock->IndexFmt = fmt;
2579 /* Handle recording of state blocks */
2580 if (This->isRecordingState) {
2581 TRACE("Recording... not performing anything\n");
2582 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2583 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2584 return WINED3D_OK;
2587 if(oldIdxs != pIndexData) {
2588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2589 if(pIndexData) {
2590 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2591 IWineD3DBuffer_AddRef(pIndexData);
2593 if(oldIdxs) {
2594 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2595 IWineD3DBuffer_Release(oldIdxs);
2599 return WINED3D_OK;
2602 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 *ppIndexData = This->stateBlock->pIndexData;
2608 /* up ref count on ppindexdata */
2609 if (*ppIndexData) {
2610 IWineD3DBuffer_AddRef(*ppIndexData);
2611 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2612 }else{
2613 TRACE("(%p) No index data set\n", This);
2615 TRACE("Returning %p\n", *ppIndexData);
2617 return WINED3D_OK;
2620 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2621 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 TRACE("(%p)->(%d)\n", This, BaseIndex);
2625 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2626 TRACE("Application is setting the old value over, nothing to do\n");
2627 return WINED3D_OK;
2630 This->updateStateBlock->baseVertexIndex = BaseIndex;
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2634 return WINED3D_OK;
2636 /* The base vertex index affects the stream sources */
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : base_index %p\n", This, base_index);
2645 *base_index = This->stateBlock->baseVertexIndex;
2647 TRACE("Returning %u\n", *base_index);
2649 return WINED3D_OK;
2652 /*****
2653 * Get / Set Viewports
2654 *****/
2655 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 TRACE("(%p)\n", This);
2659 This->updateStateBlock->changed.viewport = TRUE;
2660 This->updateStateBlock->viewport = *pViewport;
2662 /* Handle recording of state blocks */
2663 if (This->isRecordingState) {
2664 TRACE("Recording... not performing anything\n");
2665 return WINED3D_OK;
2668 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2669 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2672 return WINED3D_OK;
2676 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 TRACE("(%p)\n", This);
2679 *pViewport = This->stateBlock->viewport;
2680 return WINED3D_OK;
2683 /*****
2684 * Get / Set Render States
2685 * TODO: Verify against dx9 definitions
2686 *****/
2687 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 DWORD oldValue = This->stateBlock->renderState[State];
2692 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2694 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2695 This->updateStateBlock->renderState[State] = Value;
2697 /* Handle recording of state blocks */
2698 if (This->isRecordingState) {
2699 TRACE("Recording... not performing anything\n");
2700 return WINED3D_OK;
2703 /* Compared here and not before the assignment to allow proper stateblock recording */
2704 if(Value == oldValue) {
2705 TRACE("Application is setting the old value over, nothing to do\n");
2706 } else {
2707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2710 return WINED3D_OK;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2716 *pValue = This->stateBlock->renderState[State];
2717 return WINED3D_OK;
2720 /*****
2721 * Get / Set Sampler States
2722 * TODO: Verify against dx9 definitions
2723 *****/
2725 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 DWORD oldValue;
2729 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2730 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2732 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2733 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2736 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2737 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2738 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2741 * SetSampler is designed to allow for more than the standard up to 8 textures
2742 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2743 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2745 * http://developer.nvidia.com/object/General_FAQ.html#t6
2747 * There are two new settings for GForce
2748 * the sampler one:
2749 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2750 * and the texture one:
2751 * GL_MAX_TEXTURE_COORDS_ARB.
2752 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2753 ******************/
2755 oldValue = This->stateBlock->samplerState[Sampler][Type];
2756 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2757 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2759 /* Handle recording of state blocks */
2760 if (This->isRecordingState) {
2761 TRACE("Recording... not performing anything\n");
2762 return WINED3D_OK;
2765 if(oldValue == Value) {
2766 TRACE("Application is setting the old value over, nothing to do\n");
2767 return WINED3D_OK;
2770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2772 return WINED3D_OK;
2775 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2779 This, Sampler, debug_d3dsamplerstate(Type), Type);
2781 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2782 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2785 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2786 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2787 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2789 *Value = This->stateBlock->samplerState[Sampler][Type];
2790 TRACE("(%p) : Returning %#x\n", This, *Value);
2792 return WINED3D_OK;
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2798 This->updateStateBlock->changed.scissorRect = TRUE;
2799 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2800 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2801 return WINED3D_OK;
2803 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2805 if(This->isRecordingState) {
2806 TRACE("Recording... not performing anything\n");
2807 return WINED3D_OK;
2810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2812 return WINED3D_OK;
2815 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 *pRect = This->updateStateBlock->scissorRect;
2819 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2820 return WINED3D_OK;
2823 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2825 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2827 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2829 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2830 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2832 This->updateStateBlock->vertexDecl = pDecl;
2833 This->updateStateBlock->changed.vertexDecl = TRUE;
2835 if (This->isRecordingState) {
2836 TRACE("Recording... not performing anything\n");
2837 return WINED3D_OK;
2838 } else if(pDecl == oldDecl) {
2839 /* Checked after the assignment to allow proper stateblock recording */
2840 TRACE("Application is setting the old declaration over, nothing to do\n");
2841 return WINED3D_OK;
2844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2845 return WINED3D_OK;
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2853 *ppDecl = This->stateBlock->vertexDecl;
2854 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2855 return WINED3D_OK;
2858 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2862 This->updateStateBlock->vertexShader = pShader;
2863 This->updateStateBlock->changed.vertexShader = TRUE;
2865 if (This->isRecordingState) {
2866 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2867 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2868 TRACE("Recording... not performing anything\n");
2869 return WINED3D_OK;
2870 } else if(oldShader == pShader) {
2871 /* Checked here to allow proper stateblock recording */
2872 TRACE("App is setting the old shader over, nothing to do\n");
2873 return WINED3D_OK;
2876 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2877 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2878 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 if (NULL == ppShader) {
2889 return WINED3DERR_INVALIDCALL;
2891 *ppShader = This->stateBlock->vertexShader;
2892 if( NULL != *ppShader)
2893 IWineD3DVertexShader_AddRef(*ppShader);
2895 TRACE("(%p) : returning %p\n", This, *ppShader);
2896 return WINED3D_OK;
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2900 IWineD3DDevice *iface,
2901 UINT start,
2902 CONST BOOL *srcData,
2903 UINT count) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2908 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2909 iface, srcData, start, count);
2911 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2913 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2914 for (i = 0; i < cnt; i++)
2915 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2917 for (i = start; i < cnt + start; ++i) {
2918 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2921 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2927 IWineD3DDevice *iface,
2928 UINT start,
2929 BOOL *dstData,
2930 UINT count) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 int cnt = min(count, MAX_CONST_B - start);
2935 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2936 iface, dstData, start, count);
2938 if (dstData == NULL || cnt < 0)
2939 return WINED3DERR_INVALIDCALL;
2941 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2942 return WINED3D_OK;
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2946 IWineD3DDevice *iface,
2947 UINT start,
2948 CONST int *srcData,
2949 UINT count) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2955 iface, srcData, start, count);
2957 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2959 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2960 for (i = 0; i < cnt; i++)
2961 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2962 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2964 for (i = start; i < cnt + start; ++i) {
2965 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2968 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2970 return WINED3D_OK;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2974 IWineD3DDevice *iface,
2975 UINT start,
2976 int *dstData,
2977 UINT count) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 int cnt = min(count, MAX_CONST_I - start);
2982 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2983 iface, dstData, start, count);
2985 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2986 return WINED3DERR_INVALIDCALL;
2988 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2989 return WINED3D_OK;
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2993 IWineD3DDevice *iface,
2994 UINT start,
2995 CONST float *srcData,
2996 UINT count) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 UINT i;
3001 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3002 iface, srcData, start, count);
3004 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3005 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3006 return WINED3DERR_INVALIDCALL;
3008 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3009 if(TRACE_ON(d3d)) {
3010 for (i = 0; i < count; i++)
3011 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3012 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3015 if (!This->isRecordingState)
3017 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3021 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3022 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3024 return WINED3D_OK;
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3028 IWineD3DDevice *iface,
3029 UINT start,
3030 float *dstData,
3031 UINT count) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 int cnt = min(count, This->d3d_vshader_constantF - start);
3036 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3037 iface, dstData, start, count);
3039 if (dstData == NULL || cnt < 0)
3040 return WINED3DERR_INVALIDCALL;
3042 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3043 return WINED3D_OK;
3046 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3047 DWORD i;
3048 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3054 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3056 DWORD i = This->rev_tex_unit_map[unit];
3057 DWORD j = This->texUnitMap[stage];
3059 This->texUnitMap[stage] = unit;
3060 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3062 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3065 This->rev_tex_unit_map[unit] = stage;
3066 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3068 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3072 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3073 int i;
3075 This->fixed_function_usage_map = 0;
3076 for (i = 0; i < MAX_TEXTURES; ++i) {
3077 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3078 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3079 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3080 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3081 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3082 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3083 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3084 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3086 if (color_op == WINED3DTOP_DISABLE) {
3087 /* Not used, and disable higher stages */
3088 break;
3091 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3092 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3093 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3094 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3095 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3096 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3097 This->fixed_function_usage_map |= (1 << i);
3100 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3101 This->fixed_function_usage_map |= (1 << (i + 1));
3106 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3108 unsigned int i, tex;
3109 WORD ffu_map;
3111 device_update_fixed_function_usage_map(This);
3112 ffu_map = This->fixed_function_usage_map;
3114 if (This->max_ffp_textures == gl_info->limits.texture_stages
3115 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3117 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3119 if (!(ffu_map & 1)) continue;
3121 if (This->texUnitMap[i] != i) {
3122 device_map_stage(This, i, i);
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3124 markTextureStagesDirty(This, i);
3127 return;
3130 /* Now work out the mapping */
3131 tex = 0;
3132 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3134 if (!(ffu_map & 1)) continue;
3136 if (This->texUnitMap[i] != tex) {
3137 device_map_stage(This, i, tex);
3138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3139 markTextureStagesDirty(This, i);
3142 ++tex;
3146 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3148 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3149 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3150 unsigned int i;
3152 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3153 if (sampler_type[i] && This->texUnitMap[i] != i)
3155 device_map_stage(This, i, i);
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3157 if (i < gl_info->limits.texture_stages)
3159 markTextureStagesDirty(This, i);
3165 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3166 const DWORD *vshader_sampler_tokens, DWORD unit)
3168 DWORD current_mapping = This->rev_tex_unit_map[unit];
3170 /* Not currently used */
3171 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3173 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3174 /* Used by a fragment sampler */
3176 if (!pshader_sampler_tokens) {
3177 /* No pixel shader, check fixed function */
3178 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3181 /* Pixel shader, check the shader's sampler map */
3182 return !pshader_sampler_tokens[current_mapping];
3185 /* Used by a vertex sampler */
3186 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3189 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3191 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3192 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3193 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3194 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3195 int i;
3197 if (ps) {
3198 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3200 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3201 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3202 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3205 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3206 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3207 if (vshader_sampler_type[i])
3209 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3211 /* Already mapped somewhere */
3212 continue;
3215 while (start >= 0) {
3216 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3218 device_map_stage(This, vsampler_idx, start);
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3221 --start;
3222 break;
3225 --start;
3231 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3233 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3234 BOOL vs = use_vs(This->stateBlock);
3235 BOOL ps = use_ps(This->stateBlock);
3237 * Rules are:
3238 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3239 * that would be really messy and require shader recompilation
3240 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3241 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3243 if (ps) device_map_psamplers(This, gl_info);
3244 else device_map_fixed_function_samplers(This, gl_info);
3246 if (vs) device_map_vsamplers(This, ps, gl_info);
3249 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3252 This->updateStateBlock->pixelShader = pShader;
3253 This->updateStateBlock->changed.pixelShader = TRUE;
3255 /* Handle recording of state blocks */
3256 if (This->isRecordingState) {
3257 TRACE("Recording... not performing anything\n");
3260 if (This->isRecordingState) {
3261 TRACE("Recording... not performing anything\n");
3262 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3263 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3264 return WINED3D_OK;
3267 if(pShader == oldShader) {
3268 TRACE("App is setting the old pixel shader over, nothing to do\n");
3269 return WINED3D_OK;
3272 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3273 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3275 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3278 return WINED3D_OK;
3281 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 if (NULL == ppShader) {
3285 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3286 return WINED3DERR_INVALIDCALL;
3289 *ppShader = This->stateBlock->pixelShader;
3290 if (NULL != *ppShader) {
3291 IWineD3DPixelShader_AddRef(*ppShader);
3293 TRACE("(%p) : returning %p\n", This, *ppShader);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3298 IWineD3DDevice *iface,
3299 UINT start,
3300 CONST BOOL *srcData,
3301 UINT count) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3306 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3307 iface, srcData, start, count);
3309 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3311 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3312 for (i = 0; i < cnt; i++)
3313 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3315 for (i = start; i < cnt + start; ++i) {
3316 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3319 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3321 return WINED3D_OK;
3324 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3325 IWineD3DDevice *iface,
3326 UINT start,
3327 BOOL *dstData,
3328 UINT count) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 int cnt = min(count, MAX_CONST_B - start);
3333 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3334 iface, dstData, start, count);
3336 if (dstData == NULL || cnt < 0)
3337 return WINED3DERR_INVALIDCALL;
3339 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3340 return WINED3D_OK;
3343 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3344 IWineD3DDevice *iface,
3345 UINT start,
3346 CONST int *srcData,
3347 UINT count) {
3349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3350 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3352 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3353 iface, srcData, start, count);
3355 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3357 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3358 for (i = 0; i < cnt; i++)
3359 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3360 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3362 for (i = start; i < cnt + start; ++i) {
3363 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3366 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3368 return WINED3D_OK;
3371 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3372 IWineD3DDevice *iface,
3373 UINT start,
3374 int *dstData,
3375 UINT count) {
3377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3378 int cnt = min(count, MAX_CONST_I - start);
3380 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3381 iface, dstData, start, count);
3383 if (dstData == NULL || cnt < 0)
3384 return WINED3DERR_INVALIDCALL;
3386 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3387 return WINED3D_OK;
3390 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3391 IWineD3DDevice *iface,
3392 UINT start,
3393 CONST float *srcData,
3394 UINT count) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3397 UINT i;
3399 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3400 iface, srcData, start, count);
3402 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3403 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3404 return WINED3DERR_INVALIDCALL;
3406 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3407 if(TRACE_ON(d3d)) {
3408 for (i = 0; i < count; i++)
3409 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3410 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3413 if (!This->isRecordingState)
3415 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3419 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3420 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3426 IWineD3DDevice *iface,
3427 UINT start,
3428 float *dstData,
3429 UINT count) {
3431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3432 int cnt = min(count, This->d3d_pshader_constantF - start);
3434 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3435 iface, dstData, start, count);
3437 if (dstData == NULL || cnt < 0)
3438 return WINED3DERR_INVALIDCALL;
3440 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3441 return WINED3D_OK;
3444 /* Context activation is done by the caller. */
3445 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3446 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3447 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3448 DWORD DestFVF)
3450 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3451 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3452 unsigned int i;
3453 WINED3DVIEWPORT vp;
3454 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3455 BOOL doClip;
3456 DWORD numTextures;
3458 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3460 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3463 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3465 ERR("Source has no position mask\n");
3466 return WINED3DERR_INVALIDCALL;
3469 /* We might access VBOs from this code, so hold the lock */
3470 ENTER_GL();
3472 if (dest->resource.allocatedMemory == NULL) {
3473 buffer_get_sysmem(dest);
3476 /* Get a pointer into the destination vbo(create one if none exists) and
3477 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3479 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3481 dest->flags |= WINED3D_BUFFER_CREATEBO;
3482 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3485 if (dest->buffer_object)
3487 unsigned char extrabytes = 0;
3488 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3489 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3490 * this may write 4 extra bytes beyond the area that should be written
3492 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3493 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3494 if(!dest_conv_addr) {
3495 ERR("Out of memory\n");
3496 /* Continue without storing converted vertices */
3498 dest_conv = dest_conv_addr;
3501 /* Should I clip?
3502 * a) WINED3DRS_CLIPPING is enabled
3503 * b) WINED3DVOP_CLIP is passed
3505 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3506 static BOOL warned = FALSE;
3508 * The clipping code is not quite correct. Some things need
3509 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3510 * so disable clipping for now.
3511 * (The graphics in Half-Life are broken, and my processvertices
3512 * test crashes with IDirect3DDevice3)
3513 doClip = TRUE;
3515 doClip = FALSE;
3516 if(!warned) {
3517 warned = TRUE;
3518 FIXME("Clipping is broken and disabled for now\n");
3520 } else doClip = FALSE;
3521 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3523 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3524 WINED3DTS_VIEW,
3525 &view_mat);
3526 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3527 WINED3DTS_PROJECTION,
3528 &proj_mat);
3529 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3530 WINED3DTS_WORLDMATRIX(0),
3531 &world_mat);
3533 TRACE("View mat:\n");
3534 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);
3535 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);
3536 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);
3537 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);
3539 TRACE("Proj mat:\n");
3540 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);
3541 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);
3542 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);
3543 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);
3545 TRACE("World mat:\n");
3546 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);
3547 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);
3548 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);
3549 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);
3551 /* Get the viewport */
3552 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3553 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3554 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3556 multiply_matrix(&mat,&view_mat,&world_mat);
3557 multiply_matrix(&mat,&proj_mat,&mat);
3559 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3561 for (i = 0; i < dwCount; i+= 1) {
3562 unsigned int tex_index;
3564 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3565 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3566 /* The position first */
3567 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3568 const float *p = (const float *)(element->data + i * element->stride);
3569 float x, y, z, rhw;
3570 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3572 /* Multiplication with world, view and projection matrix */
3573 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);
3574 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);
3575 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);
3576 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);
3578 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3580 /* WARNING: The following things are taken from d3d7 and were not yet checked
3581 * against d3d8 or d3d9!
3584 /* Clipping conditions: From msdn
3586 * A vertex is clipped if it does not match the following requirements
3587 * -rhw < x <= rhw
3588 * -rhw < y <= rhw
3589 * 0 < z <= rhw
3590 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3592 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3593 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3597 if( !doClip ||
3598 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3599 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3600 ( rhw > eps ) ) ) {
3602 /* "Normal" viewport transformation (not clipped)
3603 * 1) The values are divided by rhw
3604 * 2) The y axis is negative, so multiply it with -1
3605 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3606 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3607 * 4) Multiply x with Width/2 and add Width/2
3608 * 5) The same for the height
3609 * 6) Add the viewpoint X and Y to the 2D coordinates and
3610 * The minimum Z value to z
3611 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3613 * Well, basically it's simply a linear transformation into viewport
3614 * coordinates
3617 x /= rhw;
3618 y /= rhw;
3619 z /= rhw;
3621 y *= -1;
3623 x *= vp.Width / 2;
3624 y *= vp.Height / 2;
3625 z *= vp.MaxZ - vp.MinZ;
3627 x += vp.Width / 2 + vp.X;
3628 y += vp.Height / 2 + vp.Y;
3629 z += vp.MinZ;
3631 rhw = 1 / rhw;
3632 } else {
3633 /* That vertex got clipped
3634 * Contrary to OpenGL it is not dropped completely, it just
3635 * undergoes a different calculation.
3637 TRACE("Vertex got clipped\n");
3638 x += rhw;
3639 y += rhw;
3641 x /= 2;
3642 y /= 2;
3644 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3645 * outside of the main vertex buffer memory. That needs some more
3646 * investigation...
3650 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3653 ( (float *) dest_ptr)[0] = x;
3654 ( (float *) dest_ptr)[1] = y;
3655 ( (float *) dest_ptr)[2] = z;
3656 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3658 dest_ptr += 3 * sizeof(float);
3660 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3661 dest_ptr += sizeof(float);
3664 if(dest_conv) {
3665 float w = 1 / rhw;
3666 ( (float *) dest_conv)[0] = x * w;
3667 ( (float *) dest_conv)[1] = y * w;
3668 ( (float *) dest_conv)[2] = z * w;
3669 ( (float *) dest_conv)[3] = w;
3671 dest_conv += 3 * sizeof(float);
3673 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3674 dest_conv += sizeof(float);
3678 if (DestFVF & WINED3DFVF_PSIZE) {
3679 dest_ptr += sizeof(DWORD);
3680 if(dest_conv) dest_conv += sizeof(DWORD);
3682 if (DestFVF & WINED3DFVF_NORMAL) {
3683 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3684 const float *normal = (const float *)(element->data + i * element->stride);
3685 /* AFAIK this should go into the lighting information */
3686 FIXME("Didn't expect the destination to have a normal\n");
3687 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3688 if(dest_conv) {
3689 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3693 if (DestFVF & WINED3DFVF_DIFFUSE) {
3694 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3695 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3696 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3698 static BOOL warned = FALSE;
3700 if(!warned) {
3701 ERR("No diffuse color in source, but destination has one\n");
3702 warned = TRUE;
3705 *( (DWORD *) dest_ptr) = 0xffffffff;
3706 dest_ptr += sizeof(DWORD);
3708 if(dest_conv) {
3709 *( (DWORD *) dest_conv) = 0xffffffff;
3710 dest_conv += sizeof(DWORD);
3713 else {
3714 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3715 if(dest_conv) {
3716 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3717 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3718 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3719 dest_conv += sizeof(DWORD);
3724 if (DestFVF & WINED3DFVF_SPECULAR)
3726 /* What's the color value in the feedback buffer? */
3727 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3728 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3729 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3731 static BOOL warned = FALSE;
3733 if(!warned) {
3734 ERR("No specular color in source, but destination has one\n");
3735 warned = TRUE;
3738 *( (DWORD *) dest_ptr) = 0xFF000000;
3739 dest_ptr += sizeof(DWORD);
3741 if(dest_conv) {
3742 *( (DWORD *) dest_conv) = 0xFF000000;
3743 dest_conv += sizeof(DWORD);
3746 else {
3747 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3748 if(dest_conv) {
3749 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3750 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3751 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3752 dest_conv += sizeof(DWORD);
3757 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3758 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3759 const float *tex_coord = (const float *)(element->data + i * element->stride);
3760 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3762 ERR("No source texture, but destination requests one\n");
3763 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3764 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3766 else {
3767 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3768 if(dest_conv) {
3769 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3775 if(dest_conv) {
3776 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3777 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3778 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3779 dwCount * get_flexible_vertex_size(DestFVF),
3780 dest_conv_addr));
3781 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3782 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3785 LEAVE_GL();
3787 return WINED3D_OK;
3789 #undef copy_and_next
3791 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3792 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3793 DWORD DestFVF)
3795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3796 struct wined3d_stream_info stream_info;
3797 struct wined3d_context *context;
3798 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3799 HRESULT hr;
3801 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3803 if(pVertexDecl) {
3804 ERR("Output vertex declaration not implemented yet\n");
3807 /* Need any context to write to the vbo. */
3808 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3810 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3811 * control the streamIsUP flag, thus restore it afterwards.
3813 This->stateBlock->streamIsUP = FALSE;
3814 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3815 This->stateBlock->streamIsUP = streamWasUP;
3817 if(vbo || SrcStartIndex) {
3818 unsigned int i;
3819 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3820 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3822 * Also get the start index in, but only loop over all elements if there's something to add at all.
3824 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3826 struct wined3d_stream_info_element *e;
3828 if (!(stream_info.use_map & (1 << i))) continue;
3830 e = &stream_info.elements[i];
3831 if (e->buffer_object)
3833 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3834 e->buffer_object = 0;
3835 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3836 ENTER_GL();
3837 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3838 vb->buffer_object = 0;
3839 LEAVE_GL();
3841 if (e->data) e->data += e->stride * SrcStartIndex;
3845 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3846 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3848 context_release(context);
3850 return hr;
3853 /*****
3854 * Get / Set Texture Stage States
3855 * TODO: Verify against dx9 definitions
3856 *****/
3857 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3859 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3860 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3862 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3864 if (Stage >= gl_info->limits.texture_stages)
3866 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3867 Stage, gl_info->limits.texture_stages - 1);
3868 return WINED3D_OK;
3871 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3872 This->updateStateBlock->textureState[Stage][Type] = Value;
3874 if (This->isRecordingState) {
3875 TRACE("Recording... not performing anything\n");
3876 return WINED3D_OK;
3879 /* Checked after the assignments to allow proper stateblock recording */
3880 if(oldValue == Value) {
3881 TRACE("App is setting the old value over, nothing to do\n");
3882 return WINED3D_OK;
3885 if(Stage > This->stateBlock->lowest_disabled_stage &&
3886 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3887 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3888 * Changes in other states are important on disabled stages too
3890 return WINED3D_OK;
3893 if(Type == WINED3DTSS_COLOROP) {
3894 unsigned int i;
3896 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3897 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3898 * they have to be disabled
3900 * The current stage is dirtified below.
3902 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3903 TRACE("Additionally dirtifying stage %u\n", i);
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3906 This->stateBlock->lowest_disabled_stage = Stage;
3907 TRACE("New lowest disabled: %u\n", Stage);
3908 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3909 /* Previously disabled stage enabled. Stages above it may need enabling
3910 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3911 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3913 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3916 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3918 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3919 break;
3921 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3924 This->stateBlock->lowest_disabled_stage = i;
3925 TRACE("New lowest disabled: %u\n", i);
3929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3931 return WINED3D_OK;
3934 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3936 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3937 *pValue = This->updateStateBlock->textureState[Stage][Type];
3938 return WINED3D_OK;
3941 /*****
3942 * Get / Set Texture
3943 *****/
3944 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3945 DWORD stage, IWineD3DBaseTexture *texture)
3947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3948 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3949 IWineD3DBaseTexture *prev;
3951 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3953 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3954 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3956 /* Windows accepts overflowing this array... we do not. */
3957 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3959 WARN("Ignoring invalid stage %u.\n", stage);
3960 return WINED3D_OK;
3963 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3964 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3966 WARN("Rejecting attempt to set scratch texture.\n");
3967 return WINED3DERR_INVALIDCALL;
3970 This->updateStateBlock->changed.textures |= 1 << stage;
3972 prev = This->updateStateBlock->textures[stage];
3973 TRACE("Previous texture %p.\n", prev);
3975 if (texture == prev)
3977 TRACE("App is setting the same texture again, nothing to do.\n");
3978 return WINED3D_OK;
3981 TRACE("Setting new texture to %p.\n", texture);
3982 This->updateStateBlock->textures[stage] = texture;
3984 if (This->isRecordingState)
3986 TRACE("Recording... not performing anything\n");
3988 if (texture) IWineD3DBaseTexture_AddRef(texture);
3989 if (prev) IWineD3DBaseTexture_Release(prev);
3991 return WINED3D_OK;
3994 if (texture)
3996 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3997 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3998 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4000 IWineD3DBaseTexture_AddRef(texture);
4002 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4007 if (!prev && stage < gl_info->limits.texture_stages)
4009 /* The source arguments for color and alpha ops have different
4010 * meanings when a NULL texture is bound, so the COLOROP and
4011 * ALPHAOP have to be dirtified. */
4012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4016 if (bind_count == 1) t->baseTexture.sampler = stage;
4019 if (prev)
4021 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4022 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4024 IWineD3DBaseTexture_Release(prev);
4026 if (!texture && stage < gl_info->limits.texture_stages)
4028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4032 if (bind_count && t->baseTexture.sampler == stage)
4034 unsigned int i;
4036 /* Search for other stages the texture is bound to. Shouldn't
4037 * happen if applications bind textures to a single stage only. */
4038 TRACE("Searching for other stages the texture is bound to.\n");
4039 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4041 if (This->updateStateBlock->textures[i] == prev)
4043 TRACE("Texture is also bound to stage %u.\n", i);
4044 t->baseTexture.sampler = i;
4045 break;
4051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4053 return WINED3D_OK;
4056 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4059 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4061 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4062 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4065 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4066 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4067 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4070 *ppTexture=This->stateBlock->textures[Stage];
4071 if (*ppTexture)
4072 IWineD3DBaseTexture_AddRef(*ppTexture);
4074 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4076 return WINED3D_OK;
4079 /*****
4080 * Get Back Buffer
4081 *****/
4082 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4083 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4085 IWineD3DSwapChain *swapchain;
4086 HRESULT hr;
4088 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4089 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4091 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4092 if (FAILED(hr))
4094 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4095 return hr;
4098 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4099 IWineD3DSwapChain_Release(swapchain);
4100 if (FAILED(hr))
4102 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4103 return hr;
4106 return WINED3D_OK;
4109 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4111 WARN("(%p) : stub, calling idirect3d for now\n", This);
4112 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4115 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4117 IWineD3DSwapChain *swapChain;
4118 HRESULT hr;
4120 if(iSwapChain > 0) {
4121 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4122 if (hr == WINED3D_OK) {
4123 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4124 IWineD3DSwapChain_Release(swapChain);
4125 } else {
4126 FIXME("(%p) Error getting display mode\n", This);
4128 } else {
4129 /* Don't read the real display mode,
4130 but return the stored mode instead. X11 can't change the color
4131 depth, and some apps are pretty angry if they SetDisplayMode from
4132 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4134 Also don't relay to the swapchain because with ddraw it's possible
4135 that there isn't a swapchain at all */
4136 pMode->Width = This->ddraw_width;
4137 pMode->Height = This->ddraw_height;
4138 pMode->Format = This->ddraw_format;
4139 pMode->RefreshRate = 0;
4140 hr = WINED3D_OK;
4143 return hr;
4146 /*****
4147 * Stateblock related functions
4148 *****/
4150 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4152 IWineD3DStateBlock *stateblock;
4153 HRESULT hr;
4155 TRACE("(%p)\n", This);
4157 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4159 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4160 if (FAILED(hr)) return hr;
4162 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4163 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4164 This->isRecordingState = TRUE;
4166 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4168 return WINED3D_OK;
4171 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4173 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4175 if (!This->isRecordingState) {
4176 WARN("(%p) not recording! returning error\n", This);
4177 *ppStateBlock = NULL;
4178 return WINED3DERR_INVALIDCALL;
4181 stateblock_init_contained_states(object);
4183 *ppStateBlock = (IWineD3DStateBlock*) object;
4184 This->isRecordingState = FALSE;
4185 This->updateStateBlock = This->stateBlock;
4186 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4187 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4188 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4189 return WINED3D_OK;
4192 /*****
4193 * Scene related functions
4194 *****/
4195 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4196 /* At the moment we have no need for any functionality at the beginning
4197 of a scene */
4198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4199 TRACE("(%p)\n", This);
4201 if(This->inScene) {
4202 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4203 return WINED3DERR_INVALIDCALL;
4205 This->inScene = TRUE;
4206 return WINED3D_OK;
4209 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4212 struct wined3d_context *context;
4214 TRACE("(%p)\n", This);
4216 if(!This->inScene) {
4217 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4218 return WINED3DERR_INVALIDCALL;
4221 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4222 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4223 wglFlush();
4224 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4225 * fails. */
4226 context_release(context);
4228 This->inScene = FALSE;
4229 return WINED3D_OK;
4232 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4233 const RECT *pSourceRect, const RECT *pDestRect,
4234 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4236 IWineD3DSwapChain *swapChain = NULL;
4237 int i;
4238 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4240 TRACE("iface %p.\n", iface);
4242 for(i = 0 ; i < swapchains ; i ++) {
4244 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4245 TRACE("presentinng chain %d, %p\n", i, swapChain);
4246 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4247 IWineD3DSwapChain_Release(swapChain);
4250 return WINED3D_OK;
4253 /* Not called from the VTable (internal subroutine) */
4254 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4255 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4256 float Z, DWORD Stencil) {
4257 GLbitfield glMask = 0;
4258 unsigned int i;
4259 WINED3DRECT curRect;
4260 RECT vp_rect;
4261 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4262 UINT drawable_width, drawable_height;
4263 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4264 struct wined3d_context *context;
4266 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4267 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4268 * for the cleared parts, and the untouched parts.
4270 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4271 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4272 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4273 * checking all this if the dest surface is in the drawable anyway.
4275 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4276 while(1) {
4277 if(vp->X != 0 || vp->Y != 0 ||
4278 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4279 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4280 break;
4282 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4283 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4284 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4285 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4286 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4287 break;
4289 if(Count > 0 && pRects && (
4290 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4291 pRects[0].x2 < target->currentDesc.Width ||
4292 pRects[0].y2 < target->currentDesc.Height)) {
4293 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4294 break;
4296 break;
4300 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4302 target->get_drawable_size(context, &drawable_width, &drawable_height);
4304 ENTER_GL();
4306 /* Only set the values up once, as they are not changing */
4307 if (Flags & WINED3DCLEAR_STENCIL) {
4308 glClearStencil(Stencil);
4309 checkGLcall("glClearStencil");
4310 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4311 glStencilMask(0xFFFFFFFF);
4314 if (Flags & WINED3DCLEAR_ZBUFFER) {
4315 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4316 glDepthMask(GL_TRUE);
4317 glClearDepth(Z);
4318 checkGLcall("glClearDepth");
4319 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4322 if (vp->X != 0 || vp->Y != 0 ||
4323 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4324 surface_load_ds_location(This->stencilBufferTarget, context, location);
4326 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4327 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4328 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4329 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4330 surface_load_ds_location(This->stencilBufferTarget, context, location);
4332 else if (Count > 0 && pRects && (
4333 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4334 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4335 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4336 surface_load_ds_location(This->stencilBufferTarget, context, location);
4340 if (Flags & WINED3DCLEAR_TARGET) {
4341 TRACE("Clearing screen with glClear to color %x\n", Color);
4342 glClearColor(D3DCOLOR_R(Color),
4343 D3DCOLOR_G(Color),
4344 D3DCOLOR_B(Color),
4345 D3DCOLOR_A(Color));
4346 checkGLcall("glClearColor");
4348 /* Clear ALL colors! */
4349 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4350 glMask = glMask | GL_COLOR_BUFFER_BIT;
4353 vp_rect.left = vp->X;
4354 vp_rect.top = vp->Y;
4355 vp_rect.right = vp->X + vp->Width;
4356 vp_rect.bottom = vp->Y + vp->Height;
4357 if (!(Count > 0 && pRects)) {
4358 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4359 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4361 if (context->render_offscreen)
4363 glScissor(vp_rect.left, vp_rect.top,
4364 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4365 } else {
4366 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4367 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4369 checkGLcall("glScissor");
4370 glClear(glMask);
4371 checkGLcall("glClear");
4372 } else {
4373 /* Now process each rect in turn */
4374 for (i = 0; i < Count; i++) {
4375 /* Note gl uses lower left, width/height */
4376 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4377 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4378 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4380 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4381 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4382 curRect.x1, (target->currentDesc.Height - curRect.y2),
4383 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4385 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4386 * The rectangle is not cleared, no error is returned, but further rectanlges are
4387 * still cleared if they are valid
4389 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4390 TRACE("Rectangle with negative dimensions, ignoring\n");
4391 continue;
4394 if (context->render_offscreen)
4396 glScissor(curRect.x1, curRect.y1,
4397 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4398 } else {
4399 glScissor(curRect.x1, drawable_height - curRect.y2,
4400 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4402 checkGLcall("glScissor");
4404 glClear(glMask);
4405 checkGLcall("glClear");
4409 /* Restore the old values (why..?) */
4410 if (Flags & WINED3DCLEAR_STENCIL) {
4411 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4413 if (Flags & WINED3DCLEAR_TARGET) {
4414 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4415 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4416 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4417 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4418 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4420 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4421 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4423 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4425 if (Flags & WINED3DCLEAR_ZBUFFER) {
4426 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4427 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4428 surface_modify_ds_location(This->stencilBufferTarget, location);
4431 LEAVE_GL();
4433 wglFlush(); /* Flush to ensure ordering across contexts. */
4435 context_release(context);
4437 return WINED3D_OK;
4440 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4441 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4443 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4445 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4446 Count, pRects, Flags, Color, Z, Stencil);
4448 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4449 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4450 /* TODO: What about depth stencil buffers without stencil bits? */
4451 return WINED3DERR_INVALIDCALL;
4454 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4457 /*****
4458 * Drawing functions
4459 *****/
4461 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4462 WINED3DPRIMITIVETYPE primitive_type)
4464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4466 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4468 This->updateStateBlock->changed.primitive_type = TRUE;
4469 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4472 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4473 WINED3DPRIMITIVETYPE *primitive_type)
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4479 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4481 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4484 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4488 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4490 if(!This->stateBlock->vertexDecl) {
4491 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4492 return WINED3DERR_INVALIDCALL;
4495 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4496 if(This->stateBlock->streamIsUP) {
4497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4498 This->stateBlock->streamIsUP = FALSE;
4501 if(This->stateBlock->loadBaseVertexIndex != 0) {
4502 This->stateBlock->loadBaseVertexIndex = 0;
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4505 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4506 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4507 return WINED3D_OK;
4510 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 UINT idxStride = 2;
4514 IWineD3DBuffer *pIB;
4515 GLuint vbo;
4517 pIB = This->stateBlock->pIndexData;
4518 if (!pIB) {
4519 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4520 * without an index buffer set. (The first time at least...)
4521 * D3D8 simply dies, but I doubt it can do much harm to return
4522 * D3DERR_INVALIDCALL there as well. */
4523 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4524 return WINED3DERR_INVALIDCALL;
4527 if(!This->stateBlock->vertexDecl) {
4528 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4529 return WINED3DERR_INVALIDCALL;
4532 if(This->stateBlock->streamIsUP) {
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4534 This->stateBlock->streamIsUP = FALSE;
4536 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4538 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4540 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4541 idxStride = 2;
4542 } else {
4543 idxStride = 4;
4546 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4547 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4551 drawPrimitive(iface, index_count, startIndex, idxStride,
4552 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4558 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4561 IWineD3DBuffer *vb;
4563 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4564 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4566 if(!This->stateBlock->vertexDecl) {
4567 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4568 return WINED3DERR_INVALIDCALL;
4571 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4572 vb = This->stateBlock->streamSource[0];
4573 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4574 if (vb) IWineD3DBuffer_Release(vb);
4575 This->stateBlock->streamOffset[0] = 0;
4576 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4577 This->stateBlock->streamIsUP = TRUE;
4578 This->stateBlock->loadBaseVertexIndex = 0;
4580 /* TODO: Only mark dirty if drawing from a different UP address */
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4583 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4585 /* MSDN specifies stream zero settings must be set to NULL */
4586 This->stateBlock->streamStride[0] = 0;
4587 This->stateBlock->streamSource[0] = NULL;
4589 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4590 * the new stream sources or use UP drawing again
4592 return WINED3D_OK;
4595 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4596 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4597 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4599 int idxStride;
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4601 IWineD3DBuffer *vb;
4602 IWineD3DBuffer *ib;
4604 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4605 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4607 if(!This->stateBlock->vertexDecl) {
4608 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4609 return WINED3DERR_INVALIDCALL;
4612 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4613 idxStride = 2;
4614 } else {
4615 idxStride = 4;
4618 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4619 vb = This->stateBlock->streamSource[0];
4620 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4621 if (vb) IWineD3DBuffer_Release(vb);
4622 This->stateBlock->streamIsUP = TRUE;
4623 This->stateBlock->streamOffset[0] = 0;
4624 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4626 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4627 This->stateBlock->baseVertexIndex = 0;
4628 This->stateBlock->loadBaseVertexIndex = 0;
4629 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4633 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4635 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4636 This->stateBlock->streamSource[0] = NULL;
4637 This->stateBlock->streamStride[0] = 0;
4638 ib = This->stateBlock->pIndexData;
4639 if(ib) {
4640 IWineD3DBuffer_Release(ib);
4641 This->stateBlock->pIndexData = NULL;
4643 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4644 * SetStreamSource to specify a vertex buffer
4647 return WINED3D_OK;
4650 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4651 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4655 /* Mark the state dirty until we have nicer tracking
4656 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4657 * that value.
4659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4661 This->stateBlock->baseVertexIndex = 0;
4662 This->up_strided = DrawPrimStrideData;
4663 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4664 This->up_strided = NULL;
4665 return WINED3D_OK;
4668 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4669 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4670 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4673 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4675 /* Mark the state dirty until we have nicer tracking
4676 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4677 * that value.
4679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4681 This->stateBlock->streamIsUP = TRUE;
4682 This->stateBlock->baseVertexIndex = 0;
4683 This->up_strided = DrawPrimStrideData;
4684 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4685 This->up_strided = NULL;
4686 return WINED3D_OK;
4689 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4690 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4691 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4693 WINED3DLOCKED_BOX src;
4694 WINED3DLOCKED_BOX dst;
4695 HRESULT hr;
4697 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4698 iface, pSourceVolume, pDestinationVolume);
4700 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4701 * dirtification to improve loading performance.
4703 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4704 if(FAILED(hr)) return hr;
4705 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4706 if(FAILED(hr)) {
4707 IWineD3DVolume_UnlockBox(pSourceVolume);
4708 return hr;
4711 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4713 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4714 if(FAILED(hr)) {
4715 IWineD3DVolume_UnlockBox(pSourceVolume);
4716 } else {
4717 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4719 return hr;
4722 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4723 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4725 unsigned int level_count, i;
4726 WINED3DRESOURCETYPE type;
4727 HRESULT hr;
4729 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4731 /* Verify that the source and destination textures are non-NULL. */
4732 if (!src_texture || !dst_texture)
4734 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4735 return WINED3DERR_INVALIDCALL;
4738 if (src_texture == dst_texture)
4740 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4741 return WINED3DERR_INVALIDCALL;
4744 /* Verify that the source and destination textures are the same type. */
4745 type = IWineD3DBaseTexture_GetType(src_texture);
4746 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4748 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4749 return WINED3DERR_INVALIDCALL;
4752 /* Check that both textures have the identical numbers of levels. */
4753 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4754 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4756 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4757 return WINED3DERR_INVALIDCALL;
4760 /* Make sure that the destination texture is loaded. */
4761 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4763 /* Update every surface level of the texture. */
4764 switch (type)
4766 case WINED3DRTYPE_TEXTURE:
4768 IWineD3DSurface *src_surface;
4769 IWineD3DSurface *dst_surface;
4771 for (i = 0; i < level_count; ++i)
4773 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4774 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4775 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4776 IWineD3DSurface_Release(dst_surface);
4777 IWineD3DSurface_Release(src_surface);
4778 if (FAILED(hr))
4780 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4781 return hr;
4784 break;
4787 case WINED3DRTYPE_CUBETEXTURE:
4789 IWineD3DSurface *src_surface;
4790 IWineD3DSurface *dst_surface;
4791 WINED3DCUBEMAP_FACES face;
4793 for (i = 0; i < level_count; ++i)
4795 /* Update each cube face. */
4796 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4798 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4799 face, i, &src_surface);
4800 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4801 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4802 face, i, &dst_surface);
4803 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4804 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4805 IWineD3DSurface_Release(dst_surface);
4806 IWineD3DSurface_Release(src_surface);
4807 if (FAILED(hr))
4809 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4810 return hr;
4814 break;
4817 case WINED3DRTYPE_VOLUMETEXTURE:
4819 IWineD3DVolume *src_volume;
4820 IWineD3DVolume *dst_volume;
4822 for (i = 0; i < level_count; ++i)
4824 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4825 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4826 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4827 IWineD3DVolume_Release(dst_volume);
4828 IWineD3DVolume_Release(src_volume);
4829 if (FAILED(hr))
4831 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4832 return hr;
4835 break;
4838 default:
4839 FIXME("Unsupported texture type %#x.\n", type);
4840 return WINED3DERR_INVALIDCALL;
4843 return WINED3D_OK;
4846 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4847 IWineD3DSwapChain *swapChain;
4848 HRESULT hr;
4849 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4850 if(hr == WINED3D_OK) {
4851 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4852 IWineD3DSwapChain_Release(swapChain);
4854 return hr;
4857 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 IWineD3DBaseTextureImpl *texture;
4860 DWORD i;
4862 TRACE("(%p) : %p\n", This, pNumPasses);
4864 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4865 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4866 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4867 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4869 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4870 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4871 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4874 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4875 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4877 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4878 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4879 return E_FAIL;
4881 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4882 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4883 return E_FAIL;
4885 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4886 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4887 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4888 return E_FAIL;
4892 /* return a sensible default */
4893 *pNumPasses = 1;
4895 TRACE("returning D3D_OK\n");
4896 return WINED3D_OK;
4899 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4901 int i;
4903 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4905 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4906 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4907 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4909 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4914 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4916 int j;
4917 UINT NewSize;
4918 PALETTEENTRY **palettes;
4920 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4922 if (PaletteNumber >= MAX_PALETTES) {
4923 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4924 return WINED3DERR_INVALIDCALL;
4927 if (PaletteNumber >= This->NumberOfPalettes) {
4928 NewSize = This->NumberOfPalettes;
4929 do {
4930 NewSize *= 2;
4931 } while(PaletteNumber >= NewSize);
4932 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4933 if (!palettes) {
4934 ERR("Out of memory!\n");
4935 return E_OUTOFMEMORY;
4937 This->palettes = palettes;
4938 This->NumberOfPalettes = NewSize;
4941 if (!This->palettes[PaletteNumber]) {
4942 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4943 if (!This->palettes[PaletteNumber]) {
4944 ERR("Out of memory!\n");
4945 return E_OUTOFMEMORY;
4949 for (j = 0; j < 256; ++j) {
4950 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4951 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4952 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4953 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4955 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4956 TRACE("(%p) : returning\n", This);
4957 return WINED3D_OK;
4960 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 int j;
4963 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4964 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4965 /* What happens in such situation isn't documented; Native seems to silently abort
4966 on such conditions. Return Invalid Call. */
4967 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4968 return WINED3DERR_INVALIDCALL;
4970 for (j = 0; j < 256; ++j) {
4971 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4972 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4973 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4974 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4976 TRACE("(%p) : returning\n", This);
4977 return WINED3D_OK;
4980 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4983 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4984 (tested with reference rasterizer). Return Invalid Call. */
4985 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4986 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4987 return WINED3DERR_INVALIDCALL;
4989 /*TODO: stateblocks */
4990 if (This->currentPalette != PaletteNumber) {
4991 This->currentPalette = PaletteNumber;
4992 dirtify_p8_texture_samplers(This);
4994 TRACE("(%p) : returning\n", This);
4995 return WINED3D_OK;
4998 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5000 if (PaletteNumber == NULL) {
5001 WARN("(%p) : returning Invalid Call\n", This);
5002 return WINED3DERR_INVALIDCALL;
5004 /*TODO: stateblocks */
5005 *PaletteNumber = This->currentPalette;
5006 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5007 return WINED3D_OK;
5010 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5012 static BOOL warned;
5013 if (!warned)
5015 FIXME("(%p) : stub\n", This);
5016 warned = TRUE;
5019 This->softwareVertexProcessing = bSoftware;
5020 return WINED3D_OK;
5024 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5026 static BOOL warned;
5027 if (!warned)
5029 FIXME("(%p) : stub\n", This);
5030 warned = TRUE;
5032 return This->softwareVertexProcessing;
5035 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5036 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5038 IWineD3DSwapChain *swapchain;
5039 HRESULT hr;
5041 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5042 iface, swapchain_idx, raster_status);
5044 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5045 if (FAILED(hr))
5047 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5048 return hr;
5051 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5052 IWineD3DSwapChain_Release(swapchain);
5053 if (FAILED(hr))
5055 WARN("Failed to get raster status, hr %#x.\n", hr);
5056 return hr;
5059 return WINED3D_OK;
5062 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5064 static BOOL warned;
5065 if(nSegments != 0.0f) {
5066 if (!warned)
5068 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5069 warned = TRUE;
5072 return WINED3D_OK;
5075 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5077 static BOOL warned;
5078 if (!warned)
5080 FIXME("iface %p stub!\n", iface);
5081 warned = TRUE;
5083 return 0.0f;
5086 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5088 /** TODO: remove casts to IWineD3DSurfaceImpl
5089 * NOTE: move code to surface to accomplish this
5090 ****************************************/
5091 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5092 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5093 int srcWidth, srcHeight;
5094 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5095 WINED3DFORMAT destFormat, srcFormat;
5096 UINT destSize;
5097 int srcLeft, destLeft, destTop;
5098 WINED3DPOOL srcPool, destPool;
5099 int offset = 0;
5100 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5101 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5102 GLenum dummy;
5103 DWORD sampler;
5104 int bpp;
5105 CONVERT_TYPES convert = NO_CONVERSION;
5106 struct wined3d_context *context;
5108 WINED3DSURFACE_DESC winedesc;
5110 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5112 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5113 srcSurfaceWidth = winedesc.width;
5114 srcSurfaceHeight = winedesc.height;
5115 srcPool = winedesc.pool;
5116 srcFormat = winedesc.format;
5118 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5119 destSurfaceWidth = winedesc.width;
5120 destSurfaceHeight = winedesc.height;
5121 destPool = winedesc.pool;
5122 destFormat = winedesc.format;
5123 destSize = winedesc.size;
5125 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5126 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5127 return WINED3DERR_INVALIDCALL;
5130 /* This call loads the opengl surface directly, instead of copying the surface to the
5131 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5132 * copy in sysmem and use regular surface loading.
5134 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5135 if(convert != NO_CONVERSION) {
5136 return IWineD3DSurface_BltFast(pDestinationSurface,
5137 pDestPoint ? pDestPoint->x : 0,
5138 pDestPoint ? pDestPoint->y : 0,
5139 pSourceSurface, pSourceRect, 0);
5142 if (destFormat == WINED3DFMT_UNKNOWN) {
5143 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5144 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5146 /* Get the update surface description */
5147 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5150 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5152 ENTER_GL();
5153 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5154 checkGLcall("glActiveTextureARB");
5155 LEAVE_GL();
5157 /* Make sure the surface is loaded and up to date */
5158 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5159 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5161 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5162 dst_format_desc = dst_impl->resource.format_desc;
5164 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5165 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5166 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5167 srcLeft = pSourceRect ? pSourceRect->left : 0;
5168 destLeft = pDestPoint ? pDestPoint->x : 0;
5169 destTop = pDestPoint ? pDestPoint->y : 0;
5172 /* This function doesn't support compressed textures
5173 the pitch is just bytesPerPixel * width */
5174 if(srcWidth != srcSurfaceWidth || srcLeft ){
5175 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5176 offset += srcLeft * src_format_desc->byte_count;
5177 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5179 /* TODO DXT formats */
5181 if(pSourceRect != NULL && pSourceRect->top != 0){
5182 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5184 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5185 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5186 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5188 /* Sanity check */
5189 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5191 /* need to lock the surface to get the data */
5192 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5195 ENTER_GL();
5197 /* TODO: Cube and volume support */
5198 if(rowoffset != 0){
5199 /* not a whole row so we have to do it a line at a time */
5200 int j;
5202 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5203 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5205 for (j = destTop; j < (srcHeight + destTop); ++j)
5207 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5208 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5209 data += rowoffset;
5212 } else { /* Full width, so just write out the whole texture */
5213 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5215 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5217 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5219 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5220 FIXME("Updating part of a compressed texture is not supported.\n");
5222 if (destFormat != srcFormat)
5224 FIXME("Updating mixed format compressed textures is not supported.\n");
5226 else
5228 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5229 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5232 else
5234 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5235 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5238 checkGLcall("glTexSubImage2D");
5240 LEAVE_GL();
5241 context_release(context);
5243 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5244 sampler = This->rev_tex_unit_map[0];
5245 if (sampler != WINED3D_UNMAPPED_STAGE)
5247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5250 return WINED3D_OK;
5253 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5255 struct WineD3DRectPatch *patch;
5256 GLenum old_primitive_type;
5257 unsigned int i;
5258 struct list *e;
5259 BOOL found;
5260 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5262 if(!(Handle || pRectPatchInfo)) {
5263 /* TODO: Write a test for the return value, thus the FIXME */
5264 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5265 return WINED3DERR_INVALIDCALL;
5268 if(Handle) {
5269 i = PATCHMAP_HASHFUNC(Handle);
5270 found = FALSE;
5271 LIST_FOR_EACH(e, &This->patches[i]) {
5272 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5273 if(patch->Handle == Handle) {
5274 found = TRUE;
5275 break;
5279 if(!found) {
5280 TRACE("Patch does not exist. Creating a new one\n");
5281 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5282 patch->Handle = Handle;
5283 list_add_head(&This->patches[i], &patch->entry);
5284 } else {
5285 TRACE("Found existing patch %p\n", patch);
5287 } else {
5288 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5289 * attributes we have to tesselate, read back, and draw. This needs a patch
5290 * management structure instance. Create one.
5292 * A possible improvement is to check if a vertex shader is used, and if not directly
5293 * draw the patch.
5295 FIXME("Drawing an uncached patch. This is slow\n");
5296 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5299 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5300 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5301 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5302 HRESULT hr;
5303 TRACE("Tesselation density or patch info changed, retesselating\n");
5305 if(pRectPatchInfo) {
5306 patch->RectPatchInfo = *pRectPatchInfo;
5308 patch->numSegs[0] = pNumSegs[0];
5309 patch->numSegs[1] = pNumSegs[1];
5310 patch->numSegs[2] = pNumSegs[2];
5311 patch->numSegs[3] = pNumSegs[3];
5313 hr = tesselate_rectpatch(This, patch);
5314 if(FAILED(hr)) {
5315 WARN("Patch tesselation failed\n");
5317 /* Do not release the handle to store the params of the patch */
5318 if(!Handle) {
5319 HeapFree(GetProcessHeap(), 0, patch);
5321 return hr;
5325 This->currentPatch = patch;
5326 old_primitive_type = This->stateBlock->gl_primitive_type;
5327 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5328 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5329 This->stateBlock->gl_primitive_type = old_primitive_type;
5330 This->currentPatch = NULL;
5332 /* Destroy uncached patches */
5333 if(!Handle) {
5334 HeapFree(GetProcessHeap(), 0, patch->mem);
5335 HeapFree(GetProcessHeap(), 0, patch);
5337 return WINED3D_OK;
5340 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5341 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5343 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5344 iface, handle, segment_count, patch_info);
5346 return WINED3D_OK;
5349 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5351 int i;
5352 struct WineD3DRectPatch *patch;
5353 struct list *e;
5354 TRACE("(%p) Handle(%d)\n", This, Handle);
5356 i = PATCHMAP_HASHFUNC(Handle);
5357 LIST_FOR_EACH(e, &This->patches[i]) {
5358 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5359 if(patch->Handle == Handle) {
5360 TRACE("Deleting patch %p\n", patch);
5361 list_remove(&patch->entry);
5362 HeapFree(GetProcessHeap(), 0, patch->mem);
5363 HeapFree(GetProcessHeap(), 0, patch);
5364 return WINED3D_OK;
5368 /* TODO: Write a test for the return value */
5369 FIXME("Attempt to destroy nonexistent patch\n");
5370 return WINED3DERR_INVALIDCALL;
5373 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5374 HRESULT hr;
5375 IWineD3DSwapChain *swapchain;
5377 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5378 if (SUCCEEDED(hr)) {
5379 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5380 return swapchain;
5383 return NULL;
5386 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5387 const WINED3DRECT *rect, const float color[4])
5389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5390 struct wined3d_context *context;
5392 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5393 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5395 if (!surface_is_offscreen(surface))
5397 TRACE("Surface %p is onscreen\n", surface);
5399 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5400 ENTER_GL();
5401 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5402 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5404 else
5406 TRACE("Surface %p is offscreen\n", surface);
5408 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5409 ENTER_GL();
5410 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5411 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5412 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5415 if (rect) {
5416 glEnable(GL_SCISSOR_TEST);
5417 if(surface_is_offscreen(surface)) {
5418 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5419 } else {
5420 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5421 rect->x2 - rect->x1, rect->y2 - rect->y1);
5423 checkGLcall("glScissor");
5424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5425 } else {
5426 glDisable(GL_SCISSOR_TEST);
5428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5430 glDisable(GL_BLEND);
5431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5433 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5436 glClearColor(color[0], color[1], color[2], color[3]);
5437 glClear(GL_COLOR_BUFFER_BIT);
5438 checkGLcall("glClear");
5440 LEAVE_GL();
5442 wglFlush(); /* Flush to ensure ordering across contexts. */
5444 context_release(context);
5447 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5448 unsigned int r, g, b, a;
5449 DWORD ret;
5451 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5452 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5453 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5454 return color;
5456 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5458 a = (color & 0xff000000) >> 24;
5459 r = (color & 0x00ff0000) >> 16;
5460 g = (color & 0x0000ff00) >> 8;
5461 b = (color & 0x000000ff) >> 0;
5463 switch(destfmt)
5465 case WINED3DFMT_B5G6R5_UNORM:
5466 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5467 r = (r * 32) / 256;
5468 g = (g * 64) / 256;
5469 b = (b * 32) / 256;
5470 ret = r << 11;
5471 ret |= g << 5;
5472 ret |= b;
5473 TRACE("Returning %08x\n", ret);
5474 return ret;
5476 case WINED3DFMT_B5G5R5X1_UNORM:
5477 case WINED3DFMT_B5G5R5A1_UNORM:
5478 a = (a * 2) / 256;
5479 r = (r * 32) / 256;
5480 g = (g * 32) / 256;
5481 b = (b * 32) / 256;
5482 ret = a << 15;
5483 ret |= r << 10;
5484 ret |= g << 5;
5485 ret |= b << 0;
5486 TRACE("Returning %08x\n", ret);
5487 return ret;
5489 case WINED3DFMT_A8_UNORM:
5490 TRACE("Returning %08x\n", a);
5491 return a;
5493 case WINED3DFMT_B4G4R4X4_UNORM:
5494 case WINED3DFMT_B4G4R4A4_UNORM:
5495 a = (a * 16) / 256;
5496 r = (r * 16) / 256;
5497 g = (g * 16) / 256;
5498 b = (b * 16) / 256;
5499 ret = a << 12;
5500 ret |= r << 8;
5501 ret |= g << 4;
5502 ret |= b << 0;
5503 TRACE("Returning %08x\n", ret);
5504 return ret;
5506 case WINED3DFMT_B2G3R3_UNORM:
5507 r = (r * 8) / 256;
5508 g = (g * 8) / 256;
5509 b = (b * 4) / 256;
5510 ret = r << 5;
5511 ret |= g << 2;
5512 ret |= b << 0;
5513 TRACE("Returning %08x\n", ret);
5514 return ret;
5516 case WINED3DFMT_R8G8B8X8_UNORM:
5517 case WINED3DFMT_R8G8B8A8_UNORM:
5518 ret = a << 24;
5519 ret |= b << 16;
5520 ret |= g << 8;
5521 ret |= r << 0;
5522 TRACE("Returning %08x\n", ret);
5523 return ret;
5525 case WINED3DFMT_B10G10R10A2_UNORM:
5526 a = (a * 4) / 256;
5527 r = (r * 1024) / 256;
5528 g = (g * 1024) / 256;
5529 b = (b * 1024) / 256;
5530 ret = a << 30;
5531 ret |= r << 20;
5532 ret |= g << 10;
5533 ret |= b << 0;
5534 TRACE("Returning %08x\n", ret);
5535 return ret;
5537 case WINED3DFMT_R10G10B10A2_UNORM:
5538 a = (a * 4) / 256;
5539 r = (r * 1024) / 256;
5540 g = (g * 1024) / 256;
5541 b = (b * 1024) / 256;
5542 ret = a << 30;
5543 ret |= b << 20;
5544 ret |= g << 10;
5545 ret |= r << 0;
5546 TRACE("Returning %08x\n", ret);
5547 return ret;
5549 default:
5550 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5551 return 0;
5555 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5556 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5558 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5559 WINEDDBLTFX BltFx;
5561 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5563 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5564 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5565 return WINED3DERR_INVALIDCALL;
5568 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5569 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5570 color_fill_fbo(iface, pSurface, pRect, c);
5571 return WINED3D_OK;
5572 } else {
5573 /* Just forward this to the DirectDraw blitting engine */
5574 memset(&BltFx, 0, sizeof(BltFx));
5575 BltFx.dwSize = sizeof(BltFx);
5576 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5577 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5578 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5582 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5583 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5585 IWineD3DResource *resource;
5586 IWineD3DSurface *surface;
5587 HRESULT hr;
5589 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5590 if (FAILED(hr))
5592 ERR("Failed to get resource, hr %#x\n", hr);
5593 return;
5596 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5598 FIXME("Only supported on surface resources\n");
5599 IWineD3DResource_Release(resource);
5600 return;
5603 surface = (IWineD3DSurface *)resource;
5605 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5607 color_fill_fbo(iface, surface, NULL, color);
5609 else
5611 WINEDDBLTFX BltFx;
5612 WINED3DCOLOR c;
5614 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5616 c = ((DWORD)(color[2] * 255.0f));
5617 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5618 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5619 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5621 /* Just forward this to the DirectDraw blitting engine */
5622 memset(&BltFx, 0, sizeof(BltFx));
5623 BltFx.dwSize = sizeof(BltFx);
5624 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5625 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5626 if (FAILED(hr))
5628 ERR("Blt failed, hr %#x\n", hr);
5632 IWineD3DResource_Release(resource);
5635 /* rendertarget and depth stencil functions */
5636 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5641 ERR("(%p) : Only %d render targets are supported.\n",
5642 This, This->adapter->gl_info.limits.buffers);
5643 return WINED3DERR_INVALIDCALL;
5646 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5647 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5648 /* Note inc ref on returned surface */
5649 if(*ppRenderTarget != NULL)
5650 IWineD3DSurface_AddRef(*ppRenderTarget);
5651 return WINED3D_OK;
5654 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5655 IWineD3DSurface *Front, IWineD3DSurface *Back)
5657 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5658 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5659 IWineD3DSwapChainImpl *Swapchain;
5660 HRESULT hr;
5662 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5664 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5665 if(hr != WINED3D_OK) {
5666 ERR("Can't get the swapchain\n");
5667 return hr;
5670 /* Make sure to release the swapchain */
5671 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5673 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5674 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5675 return WINED3DERR_INVALIDCALL;
5677 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5678 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5679 return WINED3DERR_INVALIDCALL;
5682 if(Swapchain->frontBuffer != Front) {
5683 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5685 if(Swapchain->frontBuffer)
5687 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5688 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5690 Swapchain->frontBuffer = Front;
5692 if(Swapchain->frontBuffer) {
5693 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5694 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5698 if(Back && !Swapchain->backBuffer) {
5699 /* We need memory for the back buffer array - only one back buffer this way */
5700 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5701 if(!Swapchain->backBuffer) {
5702 ERR("Out of memory\n");
5703 return E_OUTOFMEMORY;
5707 if(Swapchain->backBuffer[0] != Back) {
5708 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5710 /* What to do about the context here in the case of multithreading? Not sure.
5711 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5713 WARN("No active context?\n");
5715 ENTER_GL();
5716 if(!Swapchain->backBuffer[0]) {
5717 /* GL was told to draw to the front buffer at creation,
5718 * undo that
5720 glDrawBuffer(GL_BACK);
5721 checkGLcall("glDrawBuffer(GL_BACK)");
5722 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5723 Swapchain->presentParms.BackBufferCount = 1;
5724 } else if (!Back) {
5725 /* That makes problems - disable for now */
5726 /* glDrawBuffer(GL_FRONT); */
5727 checkGLcall("glDrawBuffer(GL_FRONT)");
5728 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5729 Swapchain->presentParms.BackBufferCount = 0;
5731 LEAVE_GL();
5733 if(Swapchain->backBuffer[0])
5735 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5736 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5738 Swapchain->backBuffer[0] = Back;
5740 if(Swapchain->backBuffer[0]) {
5741 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5742 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5743 Swapchain->presentParms.BackBufferWidth = BackImpl->currentDesc.Width;
5744 Swapchain->presentParms.BackBufferHeight = BackImpl->currentDesc.Height;
5745 Swapchain->presentParms.BackBufferFormat = BackImpl->resource.format_desc->format;
5746 } else {
5747 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5748 Swapchain->backBuffer = NULL;
5753 return WINED3D_OK;
5756 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 *ppZStencilSurface = This->stencilBufferTarget;
5759 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5761 if(*ppZStencilSurface != NULL) {
5762 /* Note inc ref on returned surface */
5763 IWineD3DSurface_AddRef(*ppZStencilSurface);
5764 return WINED3D_OK;
5765 } else {
5766 return WINED3DERR_NOTFOUND;
5770 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5771 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5775 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5776 const struct wined3d_gl_info *gl_info;
5777 struct wined3d_context *context;
5778 GLenum gl_filter;
5779 POINT offset = {0, 0};
5781 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5782 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5783 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5784 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5786 switch (filter) {
5787 case WINED3DTEXF_LINEAR:
5788 gl_filter = GL_LINEAR;
5789 break;
5791 default:
5792 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5793 case WINED3DTEXF_NONE:
5794 case WINED3DTEXF_POINT:
5795 gl_filter = GL_NEAREST;
5796 break;
5799 /* Make sure the drawables are up-to-date. Note that loading the
5800 * destination surface isn't strictly required if we overwrite the
5801 * entire surface. */
5802 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5803 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5805 /* Attach src surface to src fbo */
5806 src_swapchain = get_swapchain(src_surface);
5807 dst_swapchain = get_swapchain(dst_surface);
5809 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5810 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5811 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5813 gl_info = context->gl_info;
5815 if (!surface_is_offscreen(src_surface))
5817 GLenum buffer = surface_get_gl_buffer(src_surface);
5819 TRACE("Source surface %p is onscreen\n", src_surface);
5821 if(buffer == GL_FRONT) {
5822 RECT windowsize;
5823 UINT h;
5824 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5825 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5826 h = windowsize.bottom - windowsize.top;
5827 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5828 src_rect->y1 = offset.y + h - src_rect->y1;
5829 src_rect->y2 = offset.y + h - src_rect->y2;
5830 } else {
5831 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5832 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5835 ENTER_GL();
5836 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5837 glReadBuffer(buffer);
5838 checkGLcall("glReadBuffer()");
5839 } else {
5840 TRACE("Source surface %p is offscreen\n", src_surface);
5841 ENTER_GL();
5842 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5843 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5844 glReadBuffer(GL_COLOR_ATTACHMENT0);
5845 checkGLcall("glReadBuffer()");
5846 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5848 LEAVE_GL();
5850 /* Attach dst surface to dst fbo */
5851 if (!surface_is_offscreen(dst_surface))
5853 GLenum buffer = surface_get_gl_buffer(dst_surface);
5855 TRACE("Destination surface %p is onscreen\n", dst_surface);
5857 if(buffer == GL_FRONT) {
5858 RECT windowsize;
5859 UINT h;
5860 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5861 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5862 h = windowsize.bottom - windowsize.top;
5863 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5864 dst_rect->y1 = offset.y + h - dst_rect->y1;
5865 dst_rect->y2 = offset.y + h - dst_rect->y2;
5866 } else {
5867 /* Screen coords = window coords, surface height = window height */
5868 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5869 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5872 ENTER_GL();
5873 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5874 context_set_draw_buffer(context, buffer);
5876 else
5878 TRACE("Destination surface %p is offscreen\n", dst_surface);
5880 ENTER_GL();
5881 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5882 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5883 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5884 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5886 glDisable(GL_SCISSOR_TEST);
5887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5889 if (flip) {
5890 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5891 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5892 checkGLcall("glBlitFramebuffer()");
5893 } else {
5894 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5895 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5896 checkGLcall("glBlitFramebuffer()");
5899 LEAVE_GL();
5901 wglFlush(); /* Flush to ensure ordering across contexts. */
5903 context_release(context);
5905 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5908 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5909 BOOL set_viewport) {
5910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5912 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5914 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5916 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5917 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5918 return WINED3DERR_INVALIDCALL;
5921 /* MSDN says that null disables the render target
5922 but a device must always be associated with a render target
5923 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5925 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5926 FIXME("Trying to set render target 0 to NULL\n");
5927 return WINED3DERR_INVALIDCALL;
5929 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5930 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);
5931 return WINED3DERR_INVALIDCALL;
5934 /* If we are trying to set what we already have, don't bother */
5935 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5936 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5937 return WINED3D_OK;
5939 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5940 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5941 This->render_targets[RenderTargetIndex] = pRenderTarget;
5943 /* Render target 0 is special */
5944 if(RenderTargetIndex == 0 && set_viewport) {
5945 /* Finally, reset the viewport and scissor rect as the MSDN states.
5946 * Tests show that stateblock recording is ignored, the change goes
5947 * directly into the primary stateblock.
5949 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5950 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5951 This->stateBlock->viewport.X = 0;
5952 This->stateBlock->viewport.Y = 0;
5953 This->stateBlock->viewport.MaxZ = 1.0f;
5954 This->stateBlock->viewport.MinZ = 0.0f;
5955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5957 This->stateBlock->scissorRect.top = 0;
5958 This->stateBlock->scissorRect.left = 0;
5959 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5960 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5963 return WINED3D_OK;
5966 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5968 HRESULT hr = WINED3D_OK;
5969 IWineD3DSurface *tmp;
5971 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5973 if (pNewZStencil == This->stencilBufferTarget) {
5974 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5975 } else {
5976 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5977 * depending on the renter target implementation being used.
5978 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5979 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5980 * stencil buffer and incur an extra memory overhead
5981 ******************************************************/
5983 if (This->stencilBufferTarget) {
5984 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5985 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5986 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5987 } else {
5988 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5989 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5990 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5991 context_release(context);
5995 tmp = This->stencilBufferTarget;
5996 This->stencilBufferTarget = pNewZStencil;
5997 /* should we be calling the parent or the wined3d surface? */
5998 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5999 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6000 hr = WINED3D_OK;
6002 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6003 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6010 return hr;
6013 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6014 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6016 /* TODO: the use of Impl is deprecated. */
6017 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6018 WINED3DLOCKED_RECT lockedRect;
6020 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6022 /* some basic validation checks */
6023 if(This->cursorTexture) {
6024 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6025 ENTER_GL();
6026 glDeleteTextures(1, &This->cursorTexture);
6027 LEAVE_GL();
6028 context_release(context);
6029 This->cursorTexture = 0;
6032 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6033 This->haveHardwareCursor = TRUE;
6034 else
6035 This->haveHardwareCursor = FALSE;
6037 if(pCursorBitmap) {
6038 WINED3DLOCKED_RECT rect;
6040 /* MSDN: Cursor must be A8R8G8B8 */
6041 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6043 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6044 return WINED3DERR_INVALIDCALL;
6047 /* MSDN: Cursor must be smaller than the display mode */
6048 if(pSur->currentDesc.Width > This->ddraw_width ||
6049 pSur->currentDesc.Height > This->ddraw_height) {
6050 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);
6051 return WINED3DERR_INVALIDCALL;
6054 if (!This->haveHardwareCursor) {
6055 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6057 /* Do not store the surface's pointer because the application may
6058 * release it after setting the cursor image. Windows doesn't
6059 * addref the set surface, so we can't do this either without
6060 * creating circular refcount dependencies. Copy out the gl texture
6061 * instead.
6063 This->cursorWidth = pSur->currentDesc.Width;
6064 This->cursorHeight = pSur->currentDesc.Height;
6065 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6067 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6068 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6069 struct wined3d_context *context;
6070 char *mem, *bits = rect.pBits;
6071 GLint intfmt = glDesc->glInternal;
6072 GLint format = glDesc->glFormat;
6073 GLint type = glDesc->glType;
6074 INT height = This->cursorHeight;
6075 INT width = This->cursorWidth;
6076 INT bpp = glDesc->byte_count;
6077 DWORD sampler;
6078 INT i;
6080 /* Reformat the texture memory (pitch and width can be
6081 * different) */
6082 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6083 for(i = 0; i < height; i++)
6084 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6085 IWineD3DSurface_UnlockRect(pCursorBitmap);
6087 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6089 ENTER_GL();
6091 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6093 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6094 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6097 /* Make sure that a proper texture unit is selected */
6098 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6099 checkGLcall("glActiveTextureARB");
6100 sampler = This->rev_tex_unit_map[0];
6101 if (sampler != WINED3D_UNMAPPED_STAGE)
6103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6105 /* Create a new cursor texture */
6106 glGenTextures(1, &This->cursorTexture);
6107 checkGLcall("glGenTextures");
6108 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6109 checkGLcall("glBindTexture");
6110 /* Copy the bitmap memory into the cursor texture */
6111 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6112 HeapFree(GetProcessHeap(), 0, mem);
6113 checkGLcall("glTexImage2D");
6115 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6117 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6118 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6121 LEAVE_GL();
6123 context_release(context);
6125 else
6127 FIXME("A cursor texture was not returned.\n");
6128 This->cursorTexture = 0;
6131 else
6133 /* Draw a hardware cursor */
6134 ICONINFO cursorInfo;
6135 HCURSOR cursor;
6136 /* Create and clear maskBits because it is not needed for
6137 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6138 * chunks. */
6139 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6140 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6141 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6142 WINED3DLOCK_NO_DIRTY_UPDATE |
6143 WINED3DLOCK_READONLY
6145 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6146 pSur->currentDesc.Height);
6148 cursorInfo.fIcon = FALSE;
6149 cursorInfo.xHotspot = XHotSpot;
6150 cursorInfo.yHotspot = YHotSpot;
6151 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6152 1, 1, maskBits);
6153 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6154 1, 32, lockedRect.pBits);
6155 IWineD3DSurface_UnlockRect(pCursorBitmap);
6156 /* Create our cursor and clean up. */
6157 cursor = CreateIconIndirect(&cursorInfo);
6158 SetCursor(cursor);
6159 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6160 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6161 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6162 This->hardwareCursor = cursor;
6163 HeapFree(GetProcessHeap(), 0, maskBits);
6167 This->xHotSpot = XHotSpot;
6168 This->yHotSpot = YHotSpot;
6169 return WINED3D_OK;
6172 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6174 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6176 This->xScreenSpace = XScreenSpace;
6177 This->yScreenSpace = YScreenSpace;
6179 return;
6183 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6185 BOOL oldVisible = This->bCursorVisible;
6186 POINT pt;
6188 TRACE("(%p) : visible(%d)\n", This, bShow);
6191 * When ShowCursor is first called it should make the cursor appear at the OS's last
6192 * known cursor position. Because of this, some applications just repetitively call
6193 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6195 GetCursorPos(&pt);
6196 This->xScreenSpace = pt.x;
6197 This->yScreenSpace = pt.y;
6199 if (This->haveHardwareCursor) {
6200 This->bCursorVisible = bShow;
6201 if (bShow)
6202 SetCursor(This->hardwareCursor);
6203 else
6204 SetCursor(NULL);
6206 else
6208 if (This->cursorTexture)
6209 This->bCursorVisible = bShow;
6212 return oldVisible;
6215 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6216 TRACE("checking resource %p for eviction\n", resource);
6217 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6218 TRACE("Evicting %p\n", resource);
6219 IWineD3DResource_UnLoad(resource);
6221 IWineD3DResource_Release(resource);
6222 return S_OK;
6225 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6227 TRACE("iface %p.\n", iface);
6229 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6230 return WINED3D_OK;
6233 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6235 IWineD3DDeviceImpl *device = surface->resource.device;
6236 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6238 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6239 if(surface->Flags & SFLAG_DIBSECTION) {
6240 /* Release the DC */
6241 SelectObject(surface->hDC, surface->dib.holdbitmap);
6242 DeleteDC(surface->hDC);
6243 /* Release the DIB section */
6244 DeleteObject(surface->dib.DIBsection);
6245 surface->dib.bitmap_data = NULL;
6246 surface->resource.allocatedMemory = NULL;
6247 surface->Flags &= ~SFLAG_DIBSECTION;
6249 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6250 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6251 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6252 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6254 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6255 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6256 } else {
6257 surface->pow2Width = surface->pow2Height = 1;
6258 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6259 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6261 surface->glRect.left = 0;
6262 surface->glRect.top = 0;
6263 surface->glRect.right = surface->pow2Width;
6264 surface->glRect.bottom = surface->pow2Height;
6266 if (surface->texture_name)
6268 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6269 ENTER_GL();
6270 glDeleteTextures(1, &surface->texture_name);
6271 LEAVE_GL();
6272 context_release(context);
6273 surface->texture_name = 0;
6274 surface->Flags &= ~SFLAG_CLIENT;
6276 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6277 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6278 surface->Flags |= SFLAG_NONPOW2;
6279 } else {
6280 surface->Flags &= ~SFLAG_NONPOW2;
6282 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6283 surface->resource.allocatedMemory = NULL;
6284 surface->resource.heapMemory = NULL;
6285 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6287 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6288 * to a FBO */
6289 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6291 return E_OUTOFMEMORY;
6293 return WINED3D_OK;
6296 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6297 TRACE("Unloading resource %p\n", resource);
6298 IWineD3DResource_UnLoad(resource);
6299 IWineD3DResource_Release(resource);
6300 return S_OK;
6303 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6305 UINT i, count;
6306 WINED3DDISPLAYMODE m;
6307 HRESULT hr;
6309 /* All Windowed modes are supported, as is leaving the current mode */
6310 if(pp->Windowed) return TRUE;
6311 if(!pp->BackBufferWidth) return TRUE;
6312 if(!pp->BackBufferHeight) return TRUE;
6314 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6315 for(i = 0; i < count; i++) {
6316 memset(&m, 0, sizeof(m));
6317 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6318 if(FAILED(hr)) {
6319 ERR("EnumAdapterModes failed\n");
6321 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6322 /* Mode found, it is supported */
6323 return TRUE;
6326 /* Mode not found -> not supported */
6327 return FALSE;
6330 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6333 const struct wined3d_gl_info *gl_info;
6334 struct wined3d_context *context;
6335 IWineD3DBaseShaderImpl *shader;
6337 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6338 gl_info = context->gl_info;
6340 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6341 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6342 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6345 ENTER_GL();
6346 if(This->depth_blt_texture) {
6347 glDeleteTextures(1, &This->depth_blt_texture);
6348 This->depth_blt_texture = 0;
6350 if (This->depth_blt_rb) {
6351 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6352 This->depth_blt_rb = 0;
6353 This->depth_blt_rb_w = 0;
6354 This->depth_blt_rb_h = 0;
6356 LEAVE_GL();
6358 This->blitter->free_private(iface);
6359 This->frag_pipe->free_private(iface);
6360 This->shader_backend->shader_free_private(iface);
6361 destroy_dummy_textures(This, gl_info);
6363 context_release(context);
6365 while (This->numContexts)
6367 context_destroy(This, This->contexts[0]);
6369 HeapFree(GetProcessHeap(), 0, swapchain->context);
6370 swapchain->context = NULL;
6371 swapchain->num_contexts = 0;
6374 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6376 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6377 struct wined3d_context *context;
6378 HRESULT hr;
6379 IWineD3DSurfaceImpl *target;
6381 /* Recreate the primary swapchain's context */
6382 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6383 if (!swapchain->context)
6385 ERR("Failed to allocate memory for swapchain context array.\n");
6386 return E_OUTOFMEMORY;
6389 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6390 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6391 if (!context)
6393 WARN("Failed to create context.\n");
6394 HeapFree(GetProcessHeap(), 0, swapchain->context);
6395 return E_FAIL;
6398 swapchain->context[0] = context;
6399 swapchain->num_contexts = 1;
6400 create_dummy_textures(This);
6401 context_release(context);
6403 hr = This->shader_backend->shader_alloc_private(iface);
6404 if (FAILED(hr))
6406 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6407 goto err;
6410 hr = This->frag_pipe->alloc_private(iface);
6411 if (FAILED(hr))
6413 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6414 This->shader_backend->shader_free_private(iface);
6415 goto err;
6418 hr = This->blitter->alloc_private(iface);
6419 if (FAILED(hr))
6421 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6422 This->frag_pipe->free_private(iface);
6423 This->shader_backend->shader_free_private(iface);
6424 goto err;
6427 return WINED3D_OK;
6429 err:
6430 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6431 destroy_dummy_textures(This, context->gl_info);
6432 context_release(context);
6433 context_destroy(This, context);
6434 HeapFree(GetProcessHeap(), 0, swapchain->context);
6435 swapchain->num_contexts = 0;
6436 return hr;
6439 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6441 IWineD3DSwapChainImpl *swapchain;
6442 HRESULT hr;
6443 BOOL DisplayModeChanged = FALSE;
6444 WINED3DDISPLAYMODE mode;
6445 TRACE("(%p)\n", This);
6447 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6448 if(FAILED(hr)) {
6449 ERR("Failed to get the first implicit swapchain\n");
6450 return hr;
6453 if(!is_display_mode_supported(This, pPresentationParameters)) {
6454 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6455 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6456 pPresentationParameters->BackBufferHeight);
6457 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6458 return WINED3DERR_INVALIDCALL;
6461 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6462 * on an existing gl context, so there's no real need for recreation.
6464 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6466 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6468 TRACE("New params:\n");
6469 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6470 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6471 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6472 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6473 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6474 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6475 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6476 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6477 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6478 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6479 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6480 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6481 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6483 /* No special treatment of these parameters. Just store them */
6484 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6485 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6486 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6487 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6489 /* What to do about these? */
6490 if(pPresentationParameters->BackBufferCount != 0 &&
6491 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6492 ERR("Cannot change the back buffer count yet\n");
6494 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6495 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6496 ERR("Cannot change the back buffer format yet\n");
6498 if(pPresentationParameters->hDeviceWindow != NULL &&
6499 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6500 ERR("Cannot change the device window yet\n");
6502 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6503 HRESULT hrc;
6505 TRACE("Creating the depth stencil buffer\n");
6507 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6508 This->parent,
6509 pPresentationParameters->BackBufferWidth,
6510 pPresentationParameters->BackBufferHeight,
6511 pPresentationParameters->AutoDepthStencilFormat,
6512 pPresentationParameters->MultiSampleType,
6513 pPresentationParameters->MultiSampleQuality,
6514 FALSE,
6515 &This->auto_depth_stencil_buffer);
6517 if (FAILED(hrc)) {
6518 ERR("Failed to create the depth stencil buffer\n");
6519 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6520 return WINED3DERR_INVALIDCALL;
6524 /* Reset the depth stencil */
6525 if (pPresentationParameters->EnableAutoDepthStencil)
6526 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6527 else
6528 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6530 TRACE("Resetting stateblock\n");
6531 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6532 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6534 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6536 if(pPresentationParameters->Windowed) {
6537 mode.Width = swapchain->orig_width;
6538 mode.Height = swapchain->orig_height;
6539 mode.RefreshRate = 0;
6540 mode.Format = swapchain->presentParms.BackBufferFormat;
6541 } else {
6542 mode.Width = pPresentationParameters->BackBufferWidth;
6543 mode.Height = pPresentationParameters->BackBufferHeight;
6544 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6545 mode.Format = swapchain->presentParms.BackBufferFormat;
6548 /* Should Width == 800 && Height == 0 set 800x600? */
6549 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6550 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6551 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6553 UINT i;
6555 if(!pPresentationParameters->Windowed) {
6556 DisplayModeChanged = TRUE;
6558 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6559 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6561 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6562 if(FAILED(hr))
6564 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6565 return hr;
6568 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6569 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6570 if(FAILED(hr))
6572 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6573 return hr;
6576 if(This->auto_depth_stencil_buffer) {
6577 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6578 if(FAILED(hr))
6580 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6581 return hr;
6586 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6587 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6588 DisplayModeChanged) {
6590 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6592 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6593 if(swapchain->presentParms.Windowed) {
6594 /* switch from windowed to fs */
6595 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6596 pPresentationParameters->BackBufferHeight);
6597 } else {
6598 /* Fullscreen -> fullscreen mode change */
6599 MoveWindow(swapchain->win_handle, 0, 0,
6600 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6601 TRUE);
6603 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6604 /* Fullscreen -> windowed switch */
6605 swapchain_restore_fullscreen_window(swapchain);
6607 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6608 } else if(!pPresentationParameters->Windowed) {
6609 DWORD style = This->style, exStyle = This->exStyle;
6610 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6611 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6612 * Reset to clear up their mess. Guild Wars also loses the device during that.
6614 This->style = 0;
6615 This->exStyle = 0;
6616 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6617 pPresentationParameters->BackBufferHeight);
6618 This->style = style;
6619 This->exStyle = exStyle;
6622 /* Note: No parent needed for initial internal stateblock */
6623 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6624 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6625 else TRACE("Created stateblock %p\n", This->stateBlock);
6626 This->updateStateBlock = This->stateBlock;
6627 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6629 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6630 if(FAILED(hr)) {
6631 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6634 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6636 RECT client_rect;
6637 GetClientRect(swapchain->win_handle, &client_rect);
6639 if(!swapchain->presentParms.BackBufferCount)
6641 TRACE("Single buffered rendering\n");
6642 swapchain->render_to_fbo = FALSE;
6644 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6645 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6647 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6648 swapchain->presentParms.BackBufferWidth,
6649 swapchain->presentParms.BackBufferHeight,
6650 client_rect.right, client_rect.bottom);
6651 swapchain->render_to_fbo = TRUE;
6653 else
6655 TRACE("Rendering directly to GL_BACK\n");
6656 swapchain->render_to_fbo = FALSE;
6660 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6661 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6663 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6664 * first use
6666 return hr;
6669 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6671 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6673 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6675 return WINED3D_OK;
6679 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6681 TRACE("(%p) : pParameters %p\n", This, pParameters);
6683 *pParameters = This->createParms;
6684 return WINED3D_OK;
6687 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6688 IWineD3DSwapChain *swapchain;
6690 TRACE("Relaying to swapchain\n");
6692 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6693 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6694 IWineD3DSwapChain_Release(swapchain);
6698 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6699 IWineD3DSwapChain *swapchain;
6701 TRACE("Relaying to swapchain\n");
6703 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6704 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6705 IWineD3DSwapChain_Release(swapchain);
6710 /** ********************************************************
6711 * Notification functions
6712 ** ********************************************************/
6713 /** This function must be called in the release of a resource when ref == 0,
6714 * the contents of resource must still be correct,
6715 * any handles to other resource held by the caller must be closed
6716 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6717 *****************************************************/
6718 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6720 TRACE("(%p) : Adding resource %p\n", This, resource);
6722 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6725 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6727 TRACE("(%p) : Removing resource %p\n", This, resource);
6729 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6732 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6734 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6735 int counter;
6737 TRACE("(%p) : resource %p\n", This, resource);
6739 context_resource_released((IWineD3DDevice *)This, resource, type);
6741 switch (type) {
6742 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6743 case WINED3DRTYPE_SURFACE: {
6744 unsigned int i;
6746 if (This->d3d_initialized)
6748 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6750 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6751 This->render_targets[i] = NULL;
6754 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6755 This->stencilBufferTarget = NULL;
6759 break;
6761 case WINED3DRTYPE_TEXTURE:
6762 case WINED3DRTYPE_CUBETEXTURE:
6763 case WINED3DRTYPE_VOLUMETEXTURE:
6764 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6765 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6766 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6767 This->stateBlock->textures[counter] = NULL;
6769 if (This->updateStateBlock != This->stateBlock ){
6770 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6771 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6772 This->updateStateBlock->textures[counter] = NULL;
6776 break;
6777 case WINED3DRTYPE_VOLUME:
6778 /* TODO: nothing really? */
6779 break;
6780 case WINED3DRTYPE_BUFFER:
6782 int streamNumber;
6783 TRACE("Cleaning up stream pointers\n");
6785 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6786 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6787 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6789 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6790 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6791 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6792 This->updateStateBlock->streamSource[streamNumber] = 0;
6793 /* Set changed flag? */
6796 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) */
6797 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6798 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6799 This->stateBlock->streamSource[streamNumber] = 0;
6804 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6805 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6806 This->updateStateBlock->pIndexData = NULL;
6809 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6810 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6811 This->stateBlock->pIndexData = NULL;
6815 break;
6817 default:
6818 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6819 break;
6823 /* Remove the resource from the resourceStore */
6824 device_resource_remove(This, resource);
6826 TRACE("Resource released\n");
6830 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6832 IWineD3DResourceImpl *resource, *cursor;
6833 HRESULT ret;
6834 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6836 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6837 TRACE("enumerating resource %p\n", resource);
6838 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6839 ret = pCallback((IWineD3DResource *) resource, pData);
6840 if(ret == S_FALSE) {
6841 TRACE("Canceling enumeration\n");
6842 break;
6845 return WINED3D_OK;
6848 /**********************************************************
6849 * IWineD3DDevice VTbl follows
6850 **********************************************************/
6852 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6854 /*** IUnknown methods ***/
6855 IWineD3DDeviceImpl_QueryInterface,
6856 IWineD3DDeviceImpl_AddRef,
6857 IWineD3DDeviceImpl_Release,
6858 /*** IWineD3DDevice methods ***/
6859 IWineD3DDeviceImpl_GetParent,
6860 /*** Creation methods**/
6861 IWineD3DDeviceImpl_CreateBuffer,
6862 IWineD3DDeviceImpl_CreateVertexBuffer,
6863 IWineD3DDeviceImpl_CreateIndexBuffer,
6864 IWineD3DDeviceImpl_CreateStateBlock,
6865 IWineD3DDeviceImpl_CreateSurface,
6866 IWineD3DDeviceImpl_CreateRendertargetView,
6867 IWineD3DDeviceImpl_CreateTexture,
6868 IWineD3DDeviceImpl_CreateVolumeTexture,
6869 IWineD3DDeviceImpl_CreateVolume,
6870 IWineD3DDeviceImpl_CreateCubeTexture,
6871 IWineD3DDeviceImpl_CreateQuery,
6872 IWineD3DDeviceImpl_CreateSwapChain,
6873 IWineD3DDeviceImpl_CreateVertexDeclaration,
6874 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6875 IWineD3DDeviceImpl_CreateVertexShader,
6876 IWineD3DDeviceImpl_CreateGeometryShader,
6877 IWineD3DDeviceImpl_CreatePixelShader,
6878 IWineD3DDeviceImpl_CreatePalette,
6879 /*** Odd functions **/
6880 IWineD3DDeviceImpl_Init3D,
6881 IWineD3DDeviceImpl_InitGDI,
6882 IWineD3DDeviceImpl_Uninit3D,
6883 IWineD3DDeviceImpl_UninitGDI,
6884 IWineD3DDeviceImpl_SetMultithreaded,
6885 IWineD3DDeviceImpl_EvictManagedResources,
6886 IWineD3DDeviceImpl_GetAvailableTextureMem,
6887 IWineD3DDeviceImpl_GetBackBuffer,
6888 IWineD3DDeviceImpl_GetCreationParameters,
6889 IWineD3DDeviceImpl_GetDeviceCaps,
6890 IWineD3DDeviceImpl_GetDirect3D,
6891 IWineD3DDeviceImpl_GetDisplayMode,
6892 IWineD3DDeviceImpl_SetDisplayMode,
6893 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6894 IWineD3DDeviceImpl_GetRasterStatus,
6895 IWineD3DDeviceImpl_GetSwapChain,
6896 IWineD3DDeviceImpl_Reset,
6897 IWineD3DDeviceImpl_SetDialogBoxMode,
6898 IWineD3DDeviceImpl_SetCursorProperties,
6899 IWineD3DDeviceImpl_SetCursorPosition,
6900 IWineD3DDeviceImpl_ShowCursor,
6901 /*** Getters and setters **/
6902 IWineD3DDeviceImpl_SetClipPlane,
6903 IWineD3DDeviceImpl_GetClipPlane,
6904 IWineD3DDeviceImpl_SetClipStatus,
6905 IWineD3DDeviceImpl_GetClipStatus,
6906 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6907 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6908 IWineD3DDeviceImpl_SetDepthStencilSurface,
6909 IWineD3DDeviceImpl_GetDepthStencilSurface,
6910 IWineD3DDeviceImpl_SetGammaRamp,
6911 IWineD3DDeviceImpl_GetGammaRamp,
6912 IWineD3DDeviceImpl_SetIndexBuffer,
6913 IWineD3DDeviceImpl_GetIndexBuffer,
6914 IWineD3DDeviceImpl_SetBaseVertexIndex,
6915 IWineD3DDeviceImpl_GetBaseVertexIndex,
6916 IWineD3DDeviceImpl_SetLight,
6917 IWineD3DDeviceImpl_GetLight,
6918 IWineD3DDeviceImpl_SetLightEnable,
6919 IWineD3DDeviceImpl_GetLightEnable,
6920 IWineD3DDeviceImpl_SetMaterial,
6921 IWineD3DDeviceImpl_GetMaterial,
6922 IWineD3DDeviceImpl_SetNPatchMode,
6923 IWineD3DDeviceImpl_GetNPatchMode,
6924 IWineD3DDeviceImpl_SetPaletteEntries,
6925 IWineD3DDeviceImpl_GetPaletteEntries,
6926 IWineD3DDeviceImpl_SetPixelShader,
6927 IWineD3DDeviceImpl_GetPixelShader,
6928 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6929 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6930 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6931 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6932 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6933 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6934 IWineD3DDeviceImpl_SetRenderState,
6935 IWineD3DDeviceImpl_GetRenderState,
6936 IWineD3DDeviceImpl_SetRenderTarget,
6937 IWineD3DDeviceImpl_GetRenderTarget,
6938 IWineD3DDeviceImpl_SetFrontBackBuffers,
6939 IWineD3DDeviceImpl_SetSamplerState,
6940 IWineD3DDeviceImpl_GetSamplerState,
6941 IWineD3DDeviceImpl_SetScissorRect,
6942 IWineD3DDeviceImpl_GetScissorRect,
6943 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6944 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6945 IWineD3DDeviceImpl_SetStreamSource,
6946 IWineD3DDeviceImpl_GetStreamSource,
6947 IWineD3DDeviceImpl_SetStreamSourceFreq,
6948 IWineD3DDeviceImpl_GetStreamSourceFreq,
6949 IWineD3DDeviceImpl_SetTexture,
6950 IWineD3DDeviceImpl_GetTexture,
6951 IWineD3DDeviceImpl_SetTextureStageState,
6952 IWineD3DDeviceImpl_GetTextureStageState,
6953 IWineD3DDeviceImpl_SetTransform,
6954 IWineD3DDeviceImpl_GetTransform,
6955 IWineD3DDeviceImpl_SetVertexDeclaration,
6956 IWineD3DDeviceImpl_GetVertexDeclaration,
6957 IWineD3DDeviceImpl_SetVertexShader,
6958 IWineD3DDeviceImpl_GetVertexShader,
6959 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6960 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6961 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6962 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6963 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6964 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6965 IWineD3DDeviceImpl_SetViewport,
6966 IWineD3DDeviceImpl_GetViewport,
6967 IWineD3DDeviceImpl_MultiplyTransform,
6968 IWineD3DDeviceImpl_ValidateDevice,
6969 IWineD3DDeviceImpl_ProcessVertices,
6970 /*** State block ***/
6971 IWineD3DDeviceImpl_BeginStateBlock,
6972 IWineD3DDeviceImpl_EndStateBlock,
6973 /*** Scene management ***/
6974 IWineD3DDeviceImpl_BeginScene,
6975 IWineD3DDeviceImpl_EndScene,
6976 IWineD3DDeviceImpl_Present,
6977 IWineD3DDeviceImpl_Clear,
6978 IWineD3DDeviceImpl_ClearRendertargetView,
6979 /*** Drawing ***/
6980 IWineD3DDeviceImpl_SetPrimitiveType,
6981 IWineD3DDeviceImpl_GetPrimitiveType,
6982 IWineD3DDeviceImpl_DrawPrimitive,
6983 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6984 IWineD3DDeviceImpl_DrawPrimitiveUP,
6985 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6986 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6987 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6988 IWineD3DDeviceImpl_DrawRectPatch,
6989 IWineD3DDeviceImpl_DrawTriPatch,
6990 IWineD3DDeviceImpl_DeletePatch,
6991 IWineD3DDeviceImpl_ColorFill,
6992 IWineD3DDeviceImpl_UpdateTexture,
6993 IWineD3DDeviceImpl_UpdateSurface,
6994 IWineD3DDeviceImpl_GetFrontBufferData,
6995 /*** object tracking ***/
6996 IWineD3DDeviceImpl_EnumResources
6999 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7000 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7001 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7003 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7004 const struct fragment_pipeline *fragment_pipeline;
7005 struct shader_caps shader_caps;
7006 struct fragment_caps ffp_caps;
7007 WINED3DDISPLAYMODE mode;
7008 unsigned int i;
7009 HRESULT hr;
7011 device->lpVtbl = &IWineD3DDevice_Vtbl;
7012 device->ref = 1;
7013 device->wined3d = (IWineD3D *)wined3d;
7014 IWineD3D_AddRef(device->wined3d);
7015 device->adapter = wined3d->adapter_count ? adapter : NULL;
7016 device->parent = parent;
7017 device->device_parent = device_parent;
7018 list_init(&device->resources);
7019 list_init(&device->shaders);
7021 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7022 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7024 /* Get the initial screen setup for ddraw. */
7025 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7026 if (FAILED(hr))
7028 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7029 IWineD3D_Release(device->wined3d);
7030 return hr;
7032 device->ddraw_width = mode.Width;
7033 device->ddraw_height = mode.Height;
7034 device->ddraw_format = mode.Format;
7036 /* Save the creation parameters. */
7037 device->createParms.AdapterOrdinal = adapter_idx;
7038 device->createParms.DeviceType = device_type;
7039 device->createParms.hFocusWindow = focus_window;
7040 device->createParms.BehaviorFlags = flags;
7042 device->devType = device_type;
7043 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7045 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7046 device->shader_backend = adapter->shader_backend;
7048 memset(&shader_caps, 0, sizeof(shader_caps));
7049 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7050 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7051 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7052 device->vs_clipping = shader_caps.VSClipping;
7054 memset(&ffp_caps, 0, sizeof(ffp_caps));
7055 fragment_pipeline = adapter->fragment_pipe;
7056 device->frag_pipe = fragment_pipeline;
7057 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7058 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7060 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7061 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7062 if (FAILED(hr))
7064 ERR("Failed to compile state table, hr %#x.\n", hr);
7065 IWineD3D_Release(device->wined3d);
7066 return hr;
7069 device->blitter = adapter->blitter;
7071 return WINED3D_OK;
7075 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7076 DWORD rep = This->StateTable[state].representative;
7077 struct wined3d_context *context;
7078 DWORD idx;
7079 BYTE shift;
7080 UINT i;
7082 for(i = 0; i < This->numContexts; i++) {
7083 context = This->contexts[i];
7084 if(isStateDirty(context, rep)) continue;
7086 context->dirtyArray[context->numDirtyEntries++] = rep;
7087 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7088 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7089 context->isStateDirty[idx] |= (1 << shift);
7093 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7095 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7096 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7097 *width = device->pbufferWidth;
7098 *height = device->pbufferHeight;
7101 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7103 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7104 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7105 *width = surface->pow2Width;
7106 *height = surface->pow2Height;
7109 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7111 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7112 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7113 * current context's drawable, which is the size of the back buffer of the swapchain
7114 * the active context belongs to. The back buffer of the swapchain is stored as the
7115 * surface the context belongs to. */
7116 *width = surface->currentDesc.Width;
7117 *height = surface->currentDesc.Height;
7120 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7121 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7123 if (device->filter_messages)
7125 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7126 window, message, wparam, lparam);
7127 return DefWindowProcW(window, message, wparam, lparam);
7130 if (message == WM_DESTROY)
7132 TRACE("unregister window %p.\n", window);
7133 wined3d_unregister_window(window);
7135 if (device->focus_window == window) device->focus_window = NULL;
7136 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7139 return CallWindowProcW(proc, window, message, wparam, lparam);