push 7bb4e6a724086e39bb3a77eb03fa4dcdb495b071
[wine/hacks.git] / dlls / wined3d / device.c
blob83af654876fe59ba9d9aab92ead48ae0aaeabf03
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
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
69 return GL_POINTS;
71 case WINED3DPT_LINELIST:
72 return GL_LINES;
74 case WINED3DPT_LINESTRIP:
75 return GL_LINE_STRIP;
77 case WINED3DPT_TRIANGLELIST:
78 return GL_TRIANGLES;
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
98 default:
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
100 return GL_NONE;
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
108 case GL_POINTS:
109 return WINED3DPT_POINTLIST;
111 case GL_LINES:
112 return WINED3DPT_LINELIST;
114 case GL_LINE_STRIP:
115 return WINED3DPT_LINESTRIP;
117 case GL_TRIANGLES:
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
138 default:
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
144 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
146 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
147 *regnum = WINED3D_FFP_POSITION;
148 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
149 *regnum = WINED3D_FFP_BLENDWEIGHT;
150 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
151 *regnum = WINED3D_FFP_BLENDINDICES;
152 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
153 *regnum = WINED3D_FFP_NORMAL;
154 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
155 *regnum = WINED3D_FFP_PSIZE;
156 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
157 *regnum = WINED3D_FFP_DIFFUSE;
158 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
159 *regnum = WINED3D_FFP_SPECULAR;
160 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
161 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
162 else
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
165 *regnum = ~0U;
166 return FALSE;
169 return TRUE;
172 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
173 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
175 /* We need to deal with frequency data! */
176 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
177 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
178 const DWORD *streams = declaration->streams;
179 unsigned int i;
181 memset(stream_info, 0, sizeof(*stream_info));
183 /* Check for transformed vertices, disable vertex shader if present. */
184 stream_info->position_transformed = declaration->position_transformed;
185 if (declaration->position_transformed) use_vshader = FALSE;
187 /* Translate the declaration into strided data. */
188 for (i = 0; i < declaration->element_count; ++i)
190 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
191 GLuint buffer_object = 0;
192 const BYTE *data = NULL;
193 BOOL stride_used;
194 unsigned int idx;
195 DWORD stride;
197 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
198 element, i + 1, declaration->element_count);
200 if (!This->stateBlock->streamSource[element->input_slot]) continue;
202 stride = This->stateBlock->streamStride[element->input_slot];
203 if (This->stateBlock->streamIsUP)
205 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
206 buffer_object = 0;
207 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
209 else
211 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
214 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
215 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
216 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
217 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
218 * not, drawStridedSlow is needed, including a vertex buffer path. */
219 if (This->stateBlock->loadBaseVertexIndex < 0)
221 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
222 buffer_object = 0;
223 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
224 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
226 FIXME("System memory vertex data load offset is negative!\n");
230 if (fixup)
232 if (buffer_object) *fixup = TRUE;
233 else if (*fixup && !use_vshader
234 && (element->usage == WINED3DDECLUSAGE_COLOR
235 || element->usage == WINED3DDECLUSAGE_POSITIONT))
237 static BOOL warned = FALSE;
238 if (!warned)
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
242 warned = TRUE;
247 data += element->offset;
249 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
251 if (use_vshader)
253 if (element->output_slot == ~0U)
255 /* TODO: Assuming vertexdeclarations are usually used with the
256 * same or a similar shader, it might be worth it to store the
257 * last used output slot and try that one first. */
258 stride_used = vshader_get_input(This->stateBlock->vertexShader,
259 element->usage, element->usage_idx, &idx);
261 else
263 idx = element->output_slot;
264 stride_used = TRUE;
267 else
269 if (!element->ffp_valid)
271 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
272 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
273 stride_used = FALSE;
275 else
277 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
281 if (stride_used)
283 TRACE("Load %s array %u [usage %s, usage_idx %u, "
284 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
285 use_vshader ? "shader": "fixed function", idx,
286 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
287 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
289 stream_info->elements[idx].format_desc = element->format_desc;
290 stream_info->elements[idx].stride = stride;
291 stream_info->elements[idx].data = data;
292 stream_info->elements[idx].stream_idx = element->input_slot;
293 stream_info->elements[idx].buffer_object = buffer_object;
295 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
297 stream_info->swizzle_map |= 1 << idx;
299 stream_info->use_map |= 1 << idx;
303 /* Now call PreLoad on all the vertex buffers. In the very rare case
304 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
305 * The vertex buffer can now use the strided structure in the device instead of finding its
306 * own again.
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
309 * once in there. */
310 for (i = 0; i < stream_count; ++i)
312 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
313 if (vb) IWineD3DBuffer_PreLoad(vb);
317 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
318 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
320 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
321 e->format_desc = format_desc;
322 e->stride = strided->dwStride;
323 e->data = strided->lpData;
324 e->stream_idx = 0;
325 e->buffer_object = 0;
328 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
329 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
331 unsigned int i;
333 memset(stream_info, 0, sizeof(*stream_info));
335 if (strided->position.lpData)
336 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
337 if (strided->normal.lpData)
338 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
339 if (strided->diffuse.lpData)
340 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
341 if (strided->specular.lpData)
342 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
344 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
346 if (strided->texCoords[i].lpData)
347 stream_info_element_from_strided(This, &strided->texCoords[i],
348 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
351 stream_info->position_transformed = strided->position_transformed;
353 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
355 if (!stream_info->elements[i].format_desc) continue;
357 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
359 stream_info->swizzle_map |= 1 << i;
361 stream_info->use_map |= 1 << i;
365 /**********************************************************
366 * IUnknown parts follows
367 **********************************************************/
369 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
373 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
374 if (IsEqualGUID(riid, &IID_IUnknown)
375 || IsEqualGUID(riid, &IID_IWineD3DBase)
376 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
377 IUnknown_AddRef(iface);
378 *ppobj = This;
379 return S_OK;
381 *ppobj = NULL;
382 return E_NOINTERFACE;
385 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
387 ULONG refCount = InterlockedIncrement(&This->ref);
389 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
390 return refCount;
393 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedDecrement(&This->ref);
397 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
399 if (!refCount) {
400 UINT i;
402 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
403 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
404 This->multistate_funcs[i] = NULL;
407 /* TODO: Clean up all the surfaces and textures! */
408 /* NOTE: You must release the parent if the object was created via a callback
409 ** ***************************/
411 if (!list_empty(&This->resources)) {
412 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
413 dumpResources(&This->resources);
416 if(This->contexts) ERR("Context array not freed!\n");
417 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
418 This->haveHardwareCursor = FALSE;
420 IWineD3D_Release(This->wineD3D);
421 This->wineD3D = NULL;
422 HeapFree(GetProcessHeap(), 0, This);
423 TRACE("Freed device %p\n", This);
424 This = NULL;
426 return refCount;
429 /**********************************************************
430 * IWineD3DDevice implementation follows
431 **********************************************************/
432 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
434 *pParent = This->parent;
435 IUnknown_AddRef(This->parent);
436 return WINED3D_OK;
439 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
440 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
443 struct wined3d_buffer *object;
444 HRESULT hr;
446 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
448 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
449 if (!object)
451 ERR("Failed to allocate memory\n");
452 return E_OUTOFMEMORY;
455 object->vtbl = &wined3d_buffer_vtbl;
456 object->desc = *desc;
458 FIXME("Ignoring access flags (pool)\n");
460 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
461 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
462 if (FAILED(hr))
464 WARN("Failed to initialize resource, returning %#x\n", hr);
465 HeapFree(GetProcessHeap(), 0, object);
466 return hr;
468 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
470 TRACE("Created resource %p\n", object);
472 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
474 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
475 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
477 if (data)
479 BYTE *ptr;
481 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
482 if (FAILED(hr))
484 ERR("Failed to map buffer, hr %#x\n", hr);
485 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
486 return hr;
489 memcpy(ptr, data, desc->byte_width);
491 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
492 if (FAILED(hr))
494 ERR("Failed to unmap buffer, hr %#x\n", hr);
495 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
496 return hr;
500 *buffer = (IWineD3DBuffer *)object;
502 return WINED3D_OK;
505 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
506 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 /* Dummy format for now */
510 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
511 struct wined3d_buffer *object;
512 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
513 HRESULT hr;
514 BOOL conv;
516 if(Size == 0) {
517 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
518 *ppVertexBuffer = NULL;
519 return WINED3DERR_INVALIDCALL;
520 } else if(Pool == WINED3DPOOL_SCRATCH) {
521 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
522 * anyway, SCRATCH vertex buffers aren't usable anywhere
524 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
525 *ppVertexBuffer = NULL;
526 return WINED3DERR_INVALIDCALL;
529 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
530 if (!object)
532 ERR("Out of memory\n");
533 *ppVertexBuffer = NULL;
534 return WINED3DERR_OUTOFVIDEOMEMORY;
537 object->vtbl = &wined3d_buffer_vtbl;
538 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
539 if (FAILED(hr))
541 WARN("Failed to initialize resource, returning %#x\n", hr);
542 HeapFree(GetProcessHeap(), 0, object);
543 *ppVertexBuffer = NULL;
544 return hr;
546 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
548 TRACE("(%p) : Created resource %p\n", This, object);
550 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
552 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
553 *ppVertexBuffer = (IWineD3DBuffer *)object;
555 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
556 * drawStridedFast (half-life 2).
558 * Basically converting the vertices in the buffer is quite expensive, and observations
559 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
560 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
562 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
563 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
564 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
565 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
566 * dx7 apps.
567 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
568 * more. In this call we can convert dx7 buffers too.
570 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
571 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
572 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
573 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
574 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
575 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
576 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
577 } else if(dxVersion <= 7 && conv) {
578 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
579 } else {
580 object->flags |= WINED3D_BUFFER_CREATEBO;
582 return WINED3D_OK;
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
586 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
590 struct wined3d_buffer *object;
591 HRESULT hr;
593 TRACE("(%p) Creating index buffer\n", This);
595 /* Allocate the storage for the device */
596 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
597 if (!object)
599 ERR("Out of memory\n");
600 *ppIndexBuffer = NULL;
601 return WINED3DERR_OUTOFVIDEOMEMORY;
604 object->vtbl = &wined3d_buffer_vtbl;
605 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
606 if (FAILED(hr))
608 WARN("Failed to initialize resource, returning %#x\n", hr);
609 HeapFree(GetProcessHeap(), 0, object);
610 *ppIndexBuffer = NULL;
611 return hr;
613 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
615 TRACE("(%p) : Created resource %p\n", This, object);
617 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
619 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
620 object->flags |= WINED3D_BUFFER_CREATEBO;
623 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
624 Pool, object, object->resource.allocatedMemory);
625 *ppIndexBuffer = (IWineD3DBuffer *) object;
627 return WINED3D_OK;
630 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
633 IWineD3DStateBlockImpl *object;
634 unsigned int i, j;
635 HRESULT temp_result;
637 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
638 if(!object)
640 ERR("Out of memory\n");
641 *ppStateBlock = NULL;
642 return WINED3DERR_OUTOFVIDEOMEMORY;
645 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
646 object->wineD3DDevice = This;
647 object->parent = parent;
648 object->ref = 1;
649 object->blockType = Type;
651 *ppStateBlock = (IWineD3DStateBlock *)object;
653 for(i = 0; i < LIGHTMAP_SIZE; i++) {
654 list_init(&object->lightMap[i]);
657 temp_result = allocate_shader_constants(object);
658 if (FAILED(temp_result))
660 HeapFree(GetProcessHeap(), 0, object);
661 return temp_result;
664 /* Special case - Used during initialization to produce a placeholder stateblock
665 so other functions called can update a state block */
666 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
668 /* Don't bother increasing the reference count otherwise a device will never
669 be freed due to circular dependencies */
670 return WINED3D_OK;
673 /* Otherwise, might as well set the whole state block to the appropriate values */
674 if (This->stateBlock != NULL)
675 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
676 else
677 memset(object->streamFreq, 1, sizeof(object->streamFreq));
679 /* Reset the ref and type after kludging it */
680 object->wineD3DDevice = This;
681 object->ref = 1;
682 object->blockType = Type;
684 TRACE("Updating changed flags appropriate for type %d\n", Type);
686 if (Type == WINED3DSBT_ALL) {
688 TRACE("ALL => Pretend everything has changed\n");
689 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
691 /* Lights are not part of the changed / set structure */
692 for(j = 0; j < LIGHTMAP_SIZE; j++) {
693 struct list *e;
694 LIST_FOR_EACH(e, &object->lightMap[j]) {
695 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
696 light->changed = TRUE;
697 light->enabledChanged = TRUE;
700 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
701 object->contained_render_states[j - 1] = j;
703 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
704 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
705 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
706 object->contained_transform_states[j - 1] = j;
708 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
709 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
710 object->contained_vs_consts_f[j] = j;
712 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
713 for(j = 0; j < MAX_CONST_I; j++) {
714 object->contained_vs_consts_i[j] = j;
716 object->num_contained_vs_consts_i = MAX_CONST_I;
717 for(j = 0; j < MAX_CONST_B; j++) {
718 object->contained_vs_consts_b[j] = j;
720 object->num_contained_vs_consts_b = MAX_CONST_B;
721 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
722 object->contained_ps_consts_f[j] = j;
724 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
725 for(j = 0; j < MAX_CONST_I; j++) {
726 object->contained_ps_consts_i[j] = j;
728 object->num_contained_ps_consts_i = MAX_CONST_I;
729 for(j = 0; j < MAX_CONST_B; j++) {
730 object->contained_ps_consts_b[j] = j;
732 object->num_contained_ps_consts_b = MAX_CONST_B;
733 for(i = 0; i < MAX_TEXTURES; i++) {
734 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
736 object->contained_tss_states[object->num_contained_tss_states].stage = i;
737 object->contained_tss_states[object->num_contained_tss_states].state = j;
738 object->num_contained_tss_states++;
741 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
742 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
743 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
744 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
745 object->num_contained_sampler_states++;
749 for(i = 0; i < MAX_STREAMS; i++) {
750 if(object->streamSource[i]) {
751 IWineD3DBuffer_AddRef(object->streamSource[i]);
754 if(object->pIndexData) {
755 IWineD3DBuffer_AddRef(object->pIndexData);
757 if(object->vertexShader) {
758 IWineD3DVertexShader_AddRef(object->vertexShader);
760 if(object->pixelShader) {
761 IWineD3DPixelShader_AddRef(object->pixelShader);
764 } else if (Type == WINED3DSBT_PIXELSTATE) {
766 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
767 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
769 object->changed.pixelShader = TRUE;
771 /* Pixel Shader Constants */
772 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
773 object->contained_ps_consts_f[i] = i;
774 object->changed.pixelShaderConstantsF[i] = TRUE;
776 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
777 for (i = 0; i < MAX_CONST_B; ++i) {
778 object->contained_ps_consts_b[i] = i;
779 object->changed.pixelShaderConstantsB |= (1 << i);
781 object->num_contained_ps_consts_b = MAX_CONST_B;
782 for (i = 0; i < MAX_CONST_I; ++i) {
783 object->contained_ps_consts_i[i] = i;
784 object->changed.pixelShaderConstantsI |= (1 << i);
786 object->num_contained_ps_consts_i = MAX_CONST_I;
788 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
789 DWORD rs = SavedPixelStates_R[i];
790 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
791 object->contained_render_states[i] = rs;
793 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
794 for (j = 0; j < MAX_TEXTURES; j++) {
795 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
796 DWORD state = SavedPixelStates_T[i];
797 object->changed.textureState[j] |= 1 << state;
798 object->contained_tss_states[object->num_contained_tss_states].stage = j;
799 object->contained_tss_states[object->num_contained_tss_states].state = state;
800 object->num_contained_tss_states++;
803 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
804 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
805 DWORD state = SavedPixelStates_S[i];
806 object->changed.samplerState[j] |= 1 << state;
807 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
808 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
809 object->num_contained_sampler_states++;
812 if(object->pixelShader) {
813 IWineD3DPixelShader_AddRef(object->pixelShader);
816 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
817 * on them. This makes releasing the buffer easier
819 for(i = 0; i < MAX_STREAMS; i++) {
820 object->streamSource[i] = NULL;
822 object->pIndexData = NULL;
823 object->vertexShader = NULL;
825 } else if (Type == WINED3DSBT_VERTEXSTATE) {
827 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
828 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
830 object->changed.vertexShader = TRUE;
832 /* Vertex Shader Constants */
833 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
834 object->changed.vertexShaderConstantsF[i] = TRUE;
835 object->contained_vs_consts_f[i] = i;
837 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
838 for (i = 0; i < MAX_CONST_B; ++i) {
839 object->contained_vs_consts_b[i] = i;
840 object->changed.vertexShaderConstantsB |= (1 << i);
842 object->num_contained_vs_consts_b = MAX_CONST_B;
843 for (i = 0; i < MAX_CONST_I; ++i) {
844 object->contained_vs_consts_i[i] = i;
845 object->changed.vertexShaderConstantsI |= (1 << i);
847 object->num_contained_vs_consts_i = MAX_CONST_I;
848 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
849 DWORD rs = SavedVertexStates_R[i];
850 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
851 object->contained_render_states[i] = rs;
853 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
854 for (j = 0; j < MAX_TEXTURES; j++) {
855 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
856 DWORD state = SavedVertexStates_T[i];
857 object->changed.textureState[j] |= 1 << state;
858 object->contained_tss_states[object->num_contained_tss_states].stage = j;
859 object->contained_tss_states[object->num_contained_tss_states].state = state;
860 object->num_contained_tss_states++;
863 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
864 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
865 DWORD state = SavedVertexStates_S[i];
866 object->changed.samplerState[j] |= 1 << state;
867 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
868 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
869 object->num_contained_sampler_states++;
873 for(j = 0; j < LIGHTMAP_SIZE; j++) {
874 struct list *e;
875 LIST_FOR_EACH(e, &object->lightMap[j]) {
876 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
877 light->changed = TRUE;
878 light->enabledChanged = TRUE;
882 for(i = 0; i < MAX_STREAMS; i++) {
883 if(object->streamSource[i]) {
884 IWineD3DBuffer_AddRef(object->streamSource[i]);
887 if(object->vertexShader) {
888 IWineD3DVertexShader_AddRef(object->vertexShader);
890 object->pIndexData = NULL;
891 object->pixelShader = NULL;
892 } else {
893 FIXME("Unrecognized state block type %d\n", Type);
896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
897 return WINED3D_OK;
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
901 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
902 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
903 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
906 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
907 unsigned int Size = 1;
908 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
909 UINT mul_4w, mul_4h;
910 HRESULT hr;
912 TRACE("(%p) Create surface\n",This);
914 if(MultisampleQuality > 0) {
915 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
916 MultisampleQuality=0;
919 /** FIXME: Check that the format is supported
920 * by the device.
921 *******************************/
923 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
924 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
925 * space!
926 *********************************/
927 mul_4w = (Width + 3) & ~3;
928 mul_4h = (Height + 3) & ~3;
929 if (WINED3DFMT_UNKNOWN == Format) {
930 Size = 0;
931 } else if (Format == WINED3DFMT_DXT1) {
932 /* DXT1 is half byte per pixel */
933 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
935 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
936 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
937 Format == WINED3DFMT_ATI2N) {
938 Size = (mul_4w * glDesc->byte_count * mul_4h);
939 } else {
940 /* The pitch is a multiple of 4 bytes */
941 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
942 Size *= Height;
945 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
947 /** Create and initialise the surface resource **/
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 if (!object)
951 ERR("Out of memory\n");
952 *ppSurface = NULL;
953 return WINED3DERR_OUTOFVIDEOMEMORY;
956 /* Look at the implementation and set the correct Vtable */
957 switch(Impl)
959 case SURFACE_OPENGL:
960 /* Check if a 3D adapter is available when creating gl surfaces */
961 if (!This->adapter)
963 ERR("OpenGL surfaces are not available without opengl\n");
964 HeapFree(GetProcessHeap(), 0, object);
965 return WINED3DERR_NOTAVAILABLE;
967 object->lpVtbl = &IWineD3DSurface_Vtbl;
968 break;
970 case SURFACE_GDI:
971 object->lpVtbl = &IWineGDISurface_Vtbl;
972 break;
974 default:
975 /* To be sure to catch this */
976 ERR("Unknown requested surface implementation %d!\n", Impl);
977 HeapFree(GetProcessHeap(), 0, object);
978 return WINED3DERR_INVALIDCALL;
981 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
982 if (FAILED(hr))
984 WARN("Failed to initialize resource, returning %#x\n", hr);
985 HeapFree(GetProcessHeap(), 0, object);
986 *ppSurface = NULL;
987 return hr;
990 TRACE("(%p) : Created resource %p\n", This, object);
992 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
994 *ppSurface = (IWineD3DSurface *)object;
996 /* "Standalone" surface */
997 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
999 object->currentDesc.Width = Width;
1000 object->currentDesc.Height = Height;
1001 object->currentDesc.MultiSampleType = MultiSample;
1002 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1003 object->glDescription.level = Level;
1004 list_init(&object->overlays);
1006 /* Flags */
1007 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1008 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1009 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1010 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1012 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1014 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1015 * this function is too deep to need to care about things like this.
1016 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1017 * ****************************************/
1018 switch(Pool) {
1019 case WINED3DPOOL_SCRATCH:
1020 if(!Lockable)
1021 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1022 "which are mutually exclusive, setting lockable to TRUE\n");
1023 Lockable = TRUE;
1024 break;
1025 case WINED3DPOOL_SYSTEMMEM:
1026 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1027 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1028 case WINED3DPOOL_MANAGED:
1029 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1030 "Usage of DYNAMIC which are mutually exclusive, not doing "
1031 "anything just telling you.\n");
1032 break;
1033 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1034 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1035 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1036 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1037 break;
1038 default:
1039 FIXME("(%p) Unknown pool %d\n", This, Pool);
1040 break;
1043 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1044 FIXME("Trying to create a render target that isn't in the default pool\n");
1047 /* mark the texture as dirty so that it gets loaded first time around*/
1048 surface_add_dirty_rect(*ppSurface, NULL);
1049 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1050 This, Width, Height, Format, debug_d3dformat(Format),
1051 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1053 list_init(&object->renderbuffers);
1055 /* Call the private setup routine */
1056 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1057 if (FAILED(hr))
1059 ERR("Private setup failed, returning %#x\n", hr);
1060 IWineD3DSurface_Release(*ppSurface);
1061 *ppSurface = NULL;
1062 return hr;
1065 return hr;
1068 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1069 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1071 struct wined3d_rendertarget_view *object;
1073 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1074 if (!object)
1076 ERR("Failed to allocate memory\n");
1077 return E_OUTOFMEMORY;
1080 object->vtbl = &wined3d_rendertarget_view_vtbl;
1081 object->refcount = 1;
1082 IWineD3DResource_AddRef(resource);
1083 object->resource = resource;
1084 object->parent = parent;
1086 *rendertarget_view = (IWineD3DRendertargetView *)object;
1088 return WINED3D_OK;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1092 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1093 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1096 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1097 IWineD3DTextureImpl *object;
1098 unsigned int i;
1099 UINT tmpW;
1100 UINT tmpH;
1101 HRESULT hr;
1102 unsigned int pow2Width;
1103 unsigned int pow2Height;
1105 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1106 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1107 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1109 /* TODO: It should only be possible to create textures for formats
1110 that are reported as supported */
1111 if (WINED3DFMT_UNKNOWN >= Format) {
1112 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1113 return WINED3DERR_INVALIDCALL;
1116 /* Non-power2 support */
1117 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1119 pow2Width = Width;
1120 pow2Height = Height;
1122 else
1124 /* Find the nearest pow2 match */
1125 pow2Width = pow2Height = 1;
1126 while (pow2Width < Width) pow2Width <<= 1;
1127 while (pow2Height < Height) pow2Height <<= 1;
1129 if (pow2Width != Width || pow2Height != Height)
1131 if (Levels > 1)
1133 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1134 return WINED3DERR_INVALIDCALL;
1136 Levels = 1;
1140 /* Calculate levels for mip mapping */
1141 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1143 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1145 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1146 return WINED3DERR_INVALIDCALL;
1149 if (Levels > 1)
1151 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1152 return WINED3DERR_INVALIDCALL;
1155 Levels = 1;
1157 else if (!Levels)
1159 Levels = wined3d_log2i(max(Width, Height)) + 1;
1160 TRACE("Calculated levels = %d\n", Levels);
1163 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1164 if (!object)
1166 ERR("Out of memory\n");
1167 *ppTexture = NULL;
1168 return WINED3DERR_OUTOFVIDEOMEMORY;
1171 object->lpVtbl = &IWineD3DTexture_Vtbl;
1172 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1173 if (FAILED(hr))
1175 WARN("Failed to initialize resource, returning %#x\n", hr);
1176 HeapFree(GetProcessHeap(), 0, object);
1177 *ppTexture = NULL;
1178 return hr;
1181 TRACE("(%p) : Created resource %p\n", This, object);
1183 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1185 *ppTexture = (IWineD3DTexture *)object;
1187 basetexture_init(&object->baseTexture, Levels, Usage);
1189 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1191 object->baseTexture.minMipLookup = minMipLookup;
1192 object->baseTexture.magLookup = magLookup;
1193 } else {
1194 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1195 object->baseTexture.magLookup = magLookup_noFilter;
1198 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1199 /* Precalculated scaling for 'faked' non power of two texture coords.
1200 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1201 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1202 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1204 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1205 object->baseTexture.pow2Matrix[0] = 1.0;
1206 object->baseTexture.pow2Matrix[5] = 1.0;
1207 object->baseTexture.pow2Matrix[10] = 1.0;
1208 object->baseTexture.pow2Matrix[15] = 1.0;
1209 object->target = GL_TEXTURE_2D;
1210 object->cond_np2 = TRUE;
1211 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1212 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1213 (Width != pow2Width || Height != pow2Height) &&
1214 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1216 if ((Width != 1) || (Height != 1)) {
1217 object->baseTexture.pow2Matrix_identity = FALSE;
1220 object->baseTexture.pow2Matrix[0] = (float)Width;
1221 object->baseTexture.pow2Matrix[5] = (float)Height;
1222 object->baseTexture.pow2Matrix[10] = 1.0;
1223 object->baseTexture.pow2Matrix[15] = 1.0;
1224 object->target = GL_TEXTURE_RECTANGLE_ARB;
1225 object->cond_np2 = TRUE;
1226 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1227 } else {
1228 if ((Width != pow2Width) || (Height != pow2Height)) {
1229 object->baseTexture.pow2Matrix_identity = FALSE;
1230 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1231 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1232 } else {
1233 object->baseTexture.pow2Matrix[0] = 1.0;
1234 object->baseTexture.pow2Matrix[5] = 1.0;
1237 object->baseTexture.pow2Matrix[10] = 1.0;
1238 object->baseTexture.pow2Matrix[15] = 1.0;
1239 object->target = GL_TEXTURE_2D;
1240 object->cond_np2 = FALSE;
1242 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1244 /* Generate all the surfaces */
1245 tmpW = Width;
1246 tmpH = Height;
1247 for (i = 0; i < object->baseTexture.levels; i++)
1249 /* use the callback to create the texture surface */
1250 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1251 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1252 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1253 FIXME("Failed to create surface %p\n", object);
1254 /* clean up */
1255 object->surfaces[i] = NULL;
1256 IWineD3DTexture_Release((IWineD3DTexture *)object);
1258 *ppTexture = NULL;
1259 return hr;
1262 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1263 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1264 surface_set_texture_target(object->surfaces[i], object->target);
1265 /* calculate the next mipmap level */
1266 tmpW = max(1, tmpW >> 1);
1267 tmpH = max(1, tmpH >> 1);
1269 object->baseTexture.internal_preload = texture_internal_preload;
1271 TRACE("(%p) : Created texture %p\n", This, object);
1272 return WINED3D_OK;
1275 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1276 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1277 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1280 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1281 IWineD3DVolumeTextureImpl *object;
1282 unsigned int i;
1283 UINT tmpW;
1284 UINT tmpH;
1285 UINT tmpD;
1286 HRESULT hr;
1288 /* TODO: It should only be possible to create textures for formats
1289 that are reported as supported */
1290 if (WINED3DFMT_UNKNOWN >= Format) {
1291 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1292 return WINED3DERR_INVALIDCALL;
1294 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1295 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1296 return WINED3DERR_INVALIDCALL;
1299 /* Calculate levels for mip mapping */
1300 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1302 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1304 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1305 return WINED3DERR_INVALIDCALL;
1308 if (Levels > 1)
1310 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1311 return WINED3DERR_INVALIDCALL;
1314 Levels = 1;
1316 else if (!Levels)
1318 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1319 TRACE("Calculated levels = %d\n", Levels);
1322 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1323 if (!object)
1325 ERR("Out of memory\n");
1326 *ppVolumeTexture = NULL;
1327 return WINED3DERR_OUTOFVIDEOMEMORY;
1330 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1331 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1332 if (FAILED(hr))
1334 WARN("Failed to initialize resource, returning %#x\n", hr);
1335 HeapFree(GetProcessHeap(), 0, object);
1336 *ppVolumeTexture = NULL;
1337 return hr;
1340 TRACE("(%p) : Created resource %p\n", This, object);
1342 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1344 basetexture_init(&object->baseTexture, Levels, Usage);
1346 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1347 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1349 /* Is NP2 support for volumes needed? */
1350 object->baseTexture.pow2Matrix[ 0] = 1.0;
1351 object->baseTexture.pow2Matrix[ 5] = 1.0;
1352 object->baseTexture.pow2Matrix[10] = 1.0;
1353 object->baseTexture.pow2Matrix[15] = 1.0;
1355 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1357 object->baseTexture.minMipLookup = minMipLookup;
1358 object->baseTexture.magLookup = magLookup;
1359 } else {
1360 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1361 object->baseTexture.magLookup = magLookup_noFilter;
1364 /* Generate all the surfaces */
1365 tmpW = Width;
1366 tmpH = Height;
1367 tmpD = Depth;
1369 for (i = 0; i < object->baseTexture.levels; i++)
1371 HRESULT hr;
1372 /* Create the volume */
1373 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1374 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1375 if(FAILED(hr)) {
1376 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1377 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1378 *ppVolumeTexture = NULL;
1379 return hr;
1382 /* Set its container to this object */
1383 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1385 /* calculate the next mipmap level */
1386 tmpW = max(1, tmpW >> 1);
1387 tmpH = max(1, tmpH >> 1);
1388 tmpD = max(1, tmpD >> 1);
1390 object->baseTexture.internal_preload = volumetexture_internal_preload;
1392 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1393 TRACE("(%p) : Created volume texture %p\n", This, object);
1394 return WINED3D_OK;
1397 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1398 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1399 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1403 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1404 HRESULT hr;
1406 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1407 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1408 return WINED3DERR_INVALIDCALL;
1411 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1412 if (!object)
1414 ERR("Out of memory\n");
1415 *ppVolume = NULL;
1416 return WINED3DERR_OUTOFVIDEOMEMORY;
1419 object->lpVtbl = &IWineD3DVolume_Vtbl;
1420 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1421 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1422 if (FAILED(hr))
1424 WARN("Failed to initialize resource, returning %#x\n", hr);
1425 HeapFree(GetProcessHeap(), 0, object);
1426 *ppVolume = NULL;
1427 return hr;
1430 TRACE("(%p) : Created resource %p\n", This, object);
1432 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1434 *ppVolume = (IWineD3DVolume *)object;
1436 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1437 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1439 object->currentDesc.Width = Width;
1440 object->currentDesc.Height = Height;
1441 object->currentDesc.Depth = Depth;
1443 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1444 object->lockable = TRUE;
1445 object->locked = FALSE;
1446 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1447 object->dirty = TRUE;
1449 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1451 return WINED3D_OK;
1454 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1455 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1456 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1459 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1460 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1461 unsigned int i, j;
1462 UINT tmpW;
1463 HRESULT hr;
1464 unsigned int pow2EdgeLength;
1466 /* TODO: It should only be possible to create textures for formats
1467 that are reported as supported */
1468 if (WINED3DFMT_UNKNOWN >= Format) {
1469 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1470 return WINED3DERR_INVALIDCALL;
1473 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1474 WARN("(%p) : Tried to create not supported cube texture\n", This);
1475 return WINED3DERR_INVALIDCALL;
1478 /* Calculate levels for mip mapping */
1479 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1481 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1483 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1484 return WINED3DERR_INVALIDCALL;
1487 if (Levels > 1)
1489 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1490 return WINED3DERR_INVALIDCALL;
1493 Levels = 1;
1495 else if (!Levels)
1497 Levels = wined3d_log2i(EdgeLength) + 1;
1498 TRACE("Calculated levels = %d\n", Levels);
1501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1502 if (!object)
1504 ERR("Out of memory\n");
1505 *ppCubeTexture = NULL;
1506 return WINED3DERR_OUTOFVIDEOMEMORY;
1509 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1510 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1511 if (FAILED(hr))
1513 WARN("Failed to initialize resource, returning %#x\n", hr);
1514 HeapFree(GetProcessHeap(), 0, object);
1515 *ppCubeTexture = NULL;
1516 return hr;
1519 TRACE("(%p) : Created resource %p\n", This, object);
1521 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1523 basetexture_init(&object->baseTexture, Levels, Usage);
1525 TRACE("(%p) Create Cube Texture\n", This);
1527 /* Find the nearest pow2 match */
1528 pow2EdgeLength = 1;
1529 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1531 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1532 /* Precalculated scaling for 'faked' non power of two texture coords */
1533 object->baseTexture.pow2Matrix[ 0] = 1.0;
1534 object->baseTexture.pow2Matrix[ 5] = 1.0;
1535 object->baseTexture.pow2Matrix[10] = 1.0;
1536 object->baseTexture.pow2Matrix[15] = 1.0;
1537 } else {
1538 /* Precalculated scaling for 'faked' non power of two texture coords */
1539 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1540 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1541 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1542 object->baseTexture.pow2Matrix[15] = 1.0;
1543 object->baseTexture.pow2Matrix_identity = FALSE;
1546 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1548 object->baseTexture.minMipLookup = minMipLookup;
1549 object->baseTexture.magLookup = magLookup;
1550 } else {
1551 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1552 object->baseTexture.magLookup = magLookup_noFilter;
1555 /* Generate all the surfaces */
1556 tmpW = EdgeLength;
1557 for (i = 0; i < object->baseTexture.levels; i++) {
1559 /* Create the 6 faces */
1560 for (j = 0; j < 6; j++) {
1561 static const GLenum cube_targets[6] = {
1562 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1563 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1564 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1565 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1566 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1567 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1570 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1571 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1572 if (FAILED(hr))
1574 FIXME("(%p) Failed to create surface\n",object);
1575 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1576 *ppCubeTexture = NULL;
1577 return hr;
1579 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1580 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1581 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1583 tmpW = max(1, tmpW >> 1);
1585 object->baseTexture.internal_preload = cubetexture_internal_preload;
1587 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1588 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1589 return WINED3D_OK;
1592 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1594 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1595 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1596 const IWineD3DQueryVtbl *vtable;
1598 /* Just a check to see if we support this type of query */
1599 switch(Type) {
1600 case WINED3DQUERYTYPE_OCCLUSION:
1601 TRACE("(%p) occlusion query\n", This);
1602 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1603 hr = WINED3D_OK;
1604 else
1605 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1607 vtable = &IWineD3DOcclusionQuery_Vtbl;
1608 break;
1610 case WINED3DQUERYTYPE_EVENT:
1611 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1612 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1613 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1615 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1617 vtable = &IWineD3DEventQuery_Vtbl;
1618 hr = WINED3D_OK;
1619 break;
1621 case WINED3DQUERYTYPE_VCACHE:
1622 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1623 case WINED3DQUERYTYPE_VERTEXSTATS:
1624 case WINED3DQUERYTYPE_TIMESTAMP:
1625 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1626 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1627 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1628 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1629 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1630 case WINED3DQUERYTYPE_PIXELTIMINGS:
1631 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1632 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1633 default:
1634 /* Use the base Query vtable until we have a special one for each query */
1635 vtable = &IWineD3DQuery_Vtbl;
1636 FIXME("(%p) Unhandled query type %d\n", This, Type);
1638 if(NULL == ppQuery || hr != WINED3D_OK) {
1639 return hr;
1642 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1643 if(!object)
1645 ERR("Out of memory\n");
1646 *ppQuery = NULL;
1647 return WINED3DERR_OUTOFVIDEOMEMORY;
1650 object->lpVtbl = vtable;
1651 object->type = Type;
1652 object->state = QUERY_CREATED;
1653 object->wineD3DDevice = This;
1654 object->parent = parent;
1655 object->ref = 1;
1657 *ppQuery = (IWineD3DQuery *)object;
1659 /* allocated the 'extended' data based on the type of query requested */
1660 switch(Type){
1661 case WINED3DQUERYTYPE_OCCLUSION:
1662 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1663 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1665 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1666 TRACE("(%p) Allocating data for an occlusion query\n", This);
1668 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1669 ENTER_GL();
1670 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1671 LEAVE_GL();
1672 break;
1674 case WINED3DQUERYTYPE_EVENT:
1675 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1676 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1678 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1679 ENTER_GL();
1680 if(GL_SUPPORT(APPLE_FENCE)) {
1681 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1682 checkGLcall("glGenFencesAPPLE");
1683 } else if(GL_SUPPORT(NV_FENCE)) {
1684 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1685 checkGLcall("glGenFencesNV");
1687 LEAVE_GL();
1688 break;
1690 case WINED3DQUERYTYPE_VCACHE:
1691 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1692 case WINED3DQUERYTYPE_VERTEXSTATS:
1693 case WINED3DQUERYTYPE_TIMESTAMP:
1694 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1695 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1696 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1697 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1698 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1699 case WINED3DQUERYTYPE_PIXELTIMINGS:
1700 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1701 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1702 default:
1703 object->extendedData = 0;
1704 FIXME("(%p) Unhandled query type %d\n",This , Type);
1706 TRACE("(%p) : Created Query %p\n", This, object);
1707 return WINED3D_OK;
1710 /*****************************************************************************
1711 * IWineD3DDeviceImpl_SetupFullscreenWindow
1713 * Helper function that modifies a HWND's Style and ExStyle for proper
1714 * fullscreen use.
1716 * Params:
1717 * iface: Pointer to the IWineD3DDevice interface
1718 * window: Window to setup
1720 *****************************************************************************/
1721 static LONG fullscreen_style(LONG orig_style) {
1722 LONG style = orig_style;
1723 style &= ~WS_CAPTION;
1724 style &= ~WS_THICKFRAME;
1726 /* Make sure the window is managed, otherwise we won't get keyboard input */
1727 style |= WS_POPUP | WS_SYSMENU;
1729 return style;
1732 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1733 LONG exStyle = orig_exStyle;
1735 /* Filter out window decorations */
1736 exStyle &= ~WS_EX_WINDOWEDGE;
1737 exStyle &= ~WS_EX_CLIENTEDGE;
1739 return exStyle;
1742 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1745 LONG style, exStyle;
1746 /* Don't do anything if an original style is stored.
1747 * That shouldn't happen
1749 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1750 if (This->style || This->exStyle) {
1751 ERR("(%p): Want to change the window parameters of HWND %p, but "
1752 "another style is stored for restoration afterwards\n", This, window);
1755 /* Get the parameters and save them */
1756 style = GetWindowLongW(window, GWL_STYLE);
1757 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1758 This->style = style;
1759 This->exStyle = exStyle;
1761 style = fullscreen_style(style);
1762 exStyle = fullscreen_exStyle(exStyle);
1764 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1765 This->style, This->exStyle, style, exStyle);
1767 SetWindowLongW(window, GWL_STYLE, style);
1768 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1770 /* Inform the window about the update. */
1771 SetWindowPos(window, HWND_TOP, 0, 0,
1772 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1775 /*****************************************************************************
1776 * IWineD3DDeviceImpl_RestoreWindow
1778 * Helper function that restores a windows' properties when taking it out
1779 * of fullscreen mode
1781 * Params:
1782 * iface: Pointer to the IWineD3DDevice interface
1783 * window: Window to setup
1785 *****************************************************************************/
1786 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1788 LONG style, exStyle;
1790 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1791 * switch, do nothing
1793 if (!This->style && !This->exStyle) return;
1795 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1796 This, window, This->style, This->exStyle);
1798 style = GetWindowLongW(window, GWL_STYLE);
1799 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1801 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1802 * Some applications change it before calling Reset() when switching between windowed and
1803 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1805 if(style == fullscreen_style(This->style) &&
1806 exStyle == fullscreen_style(This->exStyle)) {
1807 SetWindowLongW(window, GWL_STYLE, This->style);
1808 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1811 /* Delete the old values */
1812 This->style = 0;
1813 This->exStyle = 0;
1815 /* Inform the window about the update */
1816 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1817 0, 0, 0, 0, /* Pos, Size, ignored */
1818 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1821 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1822 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1823 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1824 IUnknown *parent, WINED3DSURFTYPE surface_type)
1826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1828 HDC hDc;
1829 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1830 HRESULT hr;
1831 IUnknown *bufferParent;
1832 BOOL displaymode_set = FALSE;
1833 WINED3DDISPLAYMODE Mode;
1834 const struct GlPixelFormatDesc *format_desc;
1836 TRACE("(%p) : Created Additional Swap Chain\n", This);
1838 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1839 * does a device hold a reference to a swap chain giving them a lifetime of the device
1840 * or does the swap chain notify the device of its destruction.
1841 *******************************/
1843 /* Check the params */
1844 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1845 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1846 return WINED3DERR_INVALIDCALL;
1847 } else if (pPresentationParameters->BackBufferCount > 1) {
1848 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1851 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1852 if(!object)
1854 ERR("Out of memory\n");
1855 *ppSwapChain = NULL;
1856 return WINED3DERR_OUTOFVIDEOMEMORY;
1859 switch(surface_type) {
1860 case SURFACE_GDI:
1861 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1862 break;
1863 case SURFACE_OPENGL:
1864 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1865 break;
1866 case SURFACE_UNKNOWN:
1867 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1868 HeapFree(GetProcessHeap(), 0, object);
1869 return WINED3DERR_INVALIDCALL;
1871 object->wineD3DDevice = This;
1872 object->parent = parent;
1873 object->ref = 1;
1875 *ppSwapChain = (IWineD3DSwapChain *)object;
1877 /*********************
1878 * Lookup the window Handle and the relating X window handle
1879 ********************/
1881 /* Setup hwnd we are using, plus which display this equates to */
1882 object->win_handle = pPresentationParameters->hDeviceWindow;
1883 if (!object->win_handle) {
1884 object->win_handle = This->createParms.hFocusWindow;
1886 if(!pPresentationParameters->Windowed && object->win_handle) {
1887 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1888 pPresentationParameters->BackBufferWidth,
1889 pPresentationParameters->BackBufferHeight);
1892 hDc = GetDC(object->win_handle);
1893 TRACE("Using hDc %p\n", hDc);
1895 if (NULL == hDc) {
1896 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1897 return WINED3DERR_NOTAVAILABLE;
1900 /* Get info on the current display setup */
1901 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1902 object->orig_width = Mode.Width;
1903 object->orig_height = Mode.Height;
1904 object->orig_fmt = Mode.Format;
1905 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1907 if (pPresentationParameters->Windowed &&
1908 ((pPresentationParameters->BackBufferWidth == 0) ||
1909 (pPresentationParameters->BackBufferHeight == 0) ||
1910 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1912 RECT Rect;
1913 GetClientRect(object->win_handle, &Rect);
1915 if (pPresentationParameters->BackBufferWidth == 0) {
1916 pPresentationParameters->BackBufferWidth = Rect.right;
1917 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1919 if (pPresentationParameters->BackBufferHeight == 0) {
1920 pPresentationParameters->BackBufferHeight = Rect.bottom;
1921 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1923 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1924 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1925 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1929 /* Put the correct figures in the presentation parameters */
1930 TRACE("Copying across presentation parameters\n");
1931 object->presentParms = *pPresentationParameters;
1933 TRACE("calling rendertarget CB\n");
1934 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1935 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1936 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1937 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1938 if (SUCCEEDED(hr)) {
1939 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1940 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1941 if(surface_type == SURFACE_OPENGL) {
1942 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1944 } else {
1945 ERR("Failed to create the front buffer\n");
1946 goto error;
1949 /*********************
1950 * Windowed / Fullscreen
1951 *******************/
1954 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1955 * so we should really check to see if there is a fullscreen swapchain already
1956 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1957 **************************************/
1959 if (!pPresentationParameters->Windowed) {
1960 WINED3DDISPLAYMODE mode;
1963 /* Change the display settings */
1964 mode.Width = pPresentationParameters->BackBufferWidth;
1965 mode.Height = pPresentationParameters->BackBufferHeight;
1966 mode.Format = pPresentationParameters->BackBufferFormat;
1967 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1969 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1970 displaymode_set = TRUE;
1974 * Create an opengl context for the display visual
1975 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1976 * use different properties after that point in time. FIXME: How to handle when requested format
1977 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1978 * it chooses is identical to the one already being used!
1979 **********************************/
1980 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1982 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1983 if(!object->context) {
1984 ERR("Failed to create the context array\n");
1985 hr = E_OUTOFMEMORY;
1986 goto error;
1988 object->num_contexts = 1;
1990 if(surface_type == SURFACE_OPENGL) {
1991 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1992 if (!object->context[0]) {
1993 ERR("Failed to create a new context\n");
1994 hr = WINED3DERR_NOTAVAILABLE;
1995 goto error;
1996 } else {
1997 TRACE("Context created (HWND=%p, glContext=%p)\n",
1998 object->win_handle, object->context[0]->glCtx);
2002 /*********************
2003 * Create the back, front and stencil buffers
2004 *******************/
2005 if(object->presentParms.BackBufferCount > 0) {
2006 UINT i;
2008 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2009 if(!object->backBuffer) {
2010 ERR("Out of memory\n");
2011 hr = E_OUTOFMEMORY;
2012 goto error;
2015 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2016 TRACE("calling rendertarget CB\n");
2017 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2018 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2019 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2020 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2021 if(SUCCEEDED(hr)) {
2022 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2023 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2024 } else {
2025 ERR("Cannot create new back buffer\n");
2026 goto error;
2028 if(surface_type == SURFACE_OPENGL) {
2029 ENTER_GL();
2030 glDrawBuffer(GL_BACK);
2031 checkGLcall("glDrawBuffer(GL_BACK)");
2032 LEAVE_GL();
2035 } else {
2036 object->backBuffer = NULL;
2038 /* Single buffering - draw to front buffer */
2039 if(surface_type == SURFACE_OPENGL) {
2040 ENTER_GL();
2041 glDrawBuffer(GL_FRONT);
2042 checkGLcall("glDrawBuffer(GL_FRONT)");
2043 LEAVE_GL();
2047 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2048 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2049 TRACE("Creating depth stencil buffer\n");
2050 if (This->auto_depth_stencil_buffer == NULL ) {
2051 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2052 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2053 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2054 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2055 &This->auto_depth_stencil_buffer);
2056 if (SUCCEEDED(hr)) {
2057 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2058 } else {
2059 ERR("Failed to create the auto depth stencil\n");
2060 goto error;
2065 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2067 TRACE("Created swapchain %p\n", object);
2068 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2069 return WINED3D_OK;
2071 error:
2072 if (displaymode_set) {
2073 DEVMODEW devmode;
2074 RECT clip_rc;
2076 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2077 ClipCursor(NULL);
2079 /* Change the display settings */
2080 memset(&devmode, 0, sizeof(devmode));
2081 devmode.dmSize = sizeof(devmode);
2082 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2083 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2084 devmode.dmPelsWidth = object->orig_width;
2085 devmode.dmPelsHeight = object->orig_height;
2086 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2089 if (object->backBuffer) {
2090 UINT i;
2091 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2092 if(object->backBuffer[i]) {
2093 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2094 IUnknown_Release(bufferParent); /* once for the get parent */
2095 if (IUnknown_Release(bufferParent) > 0) {
2096 FIXME("(%p) Something's still holding the back buffer\n",This);
2100 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2101 object->backBuffer = NULL;
2103 if(object->context && object->context[0])
2104 DestroyContext(This, object->context[0]);
2105 if(object->frontBuffer) {
2106 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2107 IUnknown_Release(bufferParent); /* once for the get parent */
2108 if (IUnknown_Release(bufferParent) > 0) {
2109 FIXME("(%p) Something's still holding the front buffer\n",This);
2112 HeapFree(GetProcessHeap(), 0, object);
2113 return hr;
2116 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2117 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 TRACE("(%p)\n", This);
2121 return This->NumberOfSwapChains;
2124 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2126 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2128 if(iSwapChain < This->NumberOfSwapChains) {
2129 *pSwapChain = This->swapchains[iSwapChain];
2130 IWineD3DSwapChain_AddRef(*pSwapChain);
2131 TRACE("(%p) returning %p\n", This, *pSwapChain);
2132 return WINED3D_OK;
2133 } else {
2134 TRACE("Swapchain out of range\n");
2135 *pSwapChain = NULL;
2136 return WINED3DERR_INVALIDCALL;
2140 /*****
2141 * Vertex Declaration
2142 *****/
2143 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2144 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2146 IWineD3DVertexDeclarationImpl *object = NULL;
2147 HRESULT hr = WINED3D_OK;
2149 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2150 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2152 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2153 if(!object)
2155 ERR("Out of memory\n");
2156 *ppVertexDeclaration = NULL;
2157 return WINED3DERR_OUTOFVIDEOMEMORY;
2160 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2161 object->wineD3DDevice = This;
2162 object->parent = parent;
2163 object->ref = 1;
2165 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2167 hr = vertexdeclaration_init(object, elements, element_count);
2169 if(FAILED(hr)) {
2170 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2171 *ppVertexDeclaration = NULL;
2174 return hr;
2177 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2178 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2180 unsigned int idx, idx2;
2181 unsigned int offset;
2182 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2183 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2184 BOOL has_blend_idx = has_blend &&
2185 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2186 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2187 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2188 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2189 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2190 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2191 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2193 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2194 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2195 WINED3DVERTEXELEMENT *elements = NULL;
2197 unsigned int size;
2198 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2199 if (has_blend_idx) num_blends--;
2201 /* Compute declaration size */
2202 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2203 has_psize + has_diffuse + has_specular + num_textures;
2205 /* convert the declaration */
2206 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2207 if (!elements) return ~0U;
2209 idx = 0;
2210 if (has_pos) {
2211 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2212 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2213 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2215 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2216 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2217 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2219 else {
2220 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2221 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2223 elements[idx].usage_idx = 0;
2224 idx++;
2226 if (has_blend && (num_blends > 0)) {
2227 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2228 elements[idx].format = WINED3DFMT_A8R8G8B8;
2229 else {
2230 switch(num_blends) {
2231 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2232 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2233 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2234 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2235 default:
2236 ERR("Unexpected amount of blend values: %u\n", num_blends);
2239 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2240 elements[idx].usage_idx = 0;
2241 idx++;
2243 if (has_blend_idx) {
2244 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2245 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2246 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2247 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2248 elements[idx].format = WINED3DFMT_A8R8G8B8;
2249 else
2250 elements[idx].format = WINED3DFMT_R32_FLOAT;
2251 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2252 elements[idx].usage_idx = 0;
2253 idx++;
2255 if (has_normal) {
2256 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2257 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2258 elements[idx].usage_idx = 0;
2259 idx++;
2261 if (has_psize) {
2262 elements[idx].format = WINED3DFMT_R32_FLOAT;
2263 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2264 elements[idx].usage_idx = 0;
2265 idx++;
2267 if (has_diffuse) {
2268 elements[idx].format = WINED3DFMT_A8R8G8B8;
2269 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2270 elements[idx].usage_idx = 0;
2271 idx++;
2273 if (has_specular) {
2274 elements[idx].format = WINED3DFMT_A8R8G8B8;
2275 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2276 elements[idx].usage_idx = 1;
2277 idx++;
2279 for (idx2 = 0; idx2 < num_textures; idx2++) {
2280 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2281 switch (numcoords) {
2282 case WINED3DFVF_TEXTUREFORMAT1:
2283 elements[idx].format = WINED3DFMT_R32_FLOAT;
2284 break;
2285 case WINED3DFVF_TEXTUREFORMAT2:
2286 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2287 break;
2288 case WINED3DFVF_TEXTUREFORMAT3:
2289 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2290 break;
2291 case WINED3DFVF_TEXTUREFORMAT4:
2292 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2293 break;
2295 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2296 elements[idx].usage_idx = idx2;
2297 idx++;
2300 /* Now compute offsets, and initialize the rest of the fields */
2301 for (idx = 0, offset = 0; idx < size; ++idx)
2303 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2304 elements[idx].input_slot = 0;
2305 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2306 elements[idx].offset = offset;
2307 offset += format_desc->component_count * format_desc->component_size;
2310 *ppVertexElements = elements;
2311 return size;
2314 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2315 WINED3DVERTEXELEMENT* elements = NULL;
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2317 unsigned int size;
2318 DWORD hr;
2320 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2321 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2323 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2324 HeapFree(GetProcessHeap(), 0, elements);
2325 if (hr != S_OK) return hr;
2327 return WINED3D_OK;
2330 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2332 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2333 HRESULT hr = WINED3D_OK;
2335 if (!pFunction) return WINED3DERR_INVALIDCALL;
2337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2338 if (!object)
2340 ERR("Out of memory\n");
2341 *ppVertexShader = NULL;
2342 return WINED3DERR_OUTOFVIDEOMEMORY;
2345 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2346 object->parent = parent;
2347 shader_init(&object->baseShader, iface);
2348 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2349 *ppVertexShader = (IWineD3DVertexShader *)object;
2351 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2353 if (vertex_declaration) {
2354 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2357 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, NULL);
2358 if (FAILED(hr))
2360 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2361 IWineD3DVertexShader_Release(*ppVertexShader);
2362 *ppVertexShader = NULL;
2363 return hr;
2366 return hr;
2369 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2370 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2371 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2375 HRESULT hr = WINED3D_OK;
2377 if (!pFunction) return WINED3DERR_INVALIDCALL;
2379 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2380 if (!object)
2382 ERR("Out of memory\n");
2383 *ppPixelShader = NULL;
2384 return WINED3DERR_OUTOFVIDEOMEMORY;
2387 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2388 object->parent = parent;
2389 shader_init(&object->baseShader, iface);
2390 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2391 *ppPixelShader = (IWineD3DPixelShader *)object;
2393 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2395 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2396 if (FAILED(hr))
2398 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2399 IWineD3DPixelShader_Release(*ppPixelShader);
2400 *ppPixelShader = NULL;
2401 return hr;
2404 return hr;
2407 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2408 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2411 IWineD3DPaletteImpl *object;
2412 HRESULT hr;
2413 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2415 /* Create the new object */
2416 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2417 if(!object) {
2418 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2419 return E_OUTOFMEMORY;
2422 object->lpVtbl = &IWineD3DPalette_Vtbl;
2423 object->ref = 1;
2424 object->Flags = Flags;
2425 object->parent = Parent;
2426 object->wineD3DDevice = This;
2427 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2428 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2430 if(!object->hpal) {
2431 HeapFree( GetProcessHeap(), 0, object);
2432 return E_OUTOFMEMORY;
2435 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2436 if(FAILED(hr)) {
2437 IWineD3DPalette_Release((IWineD3DPalette *) object);
2438 return hr;
2441 *Palette = (IWineD3DPalette *) object;
2443 return WINED3D_OK;
2446 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2447 HBITMAP hbm;
2448 BITMAP bm;
2449 HRESULT hr;
2450 HDC dcb = NULL, dcs = NULL;
2451 WINEDDCOLORKEY colorkey;
2453 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2454 if(hbm)
2456 GetObjectA(hbm, sizeof(BITMAP), &bm);
2457 dcb = CreateCompatibleDC(NULL);
2458 if(!dcb) goto out;
2459 SelectObject(dcb, hbm);
2461 else
2463 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2464 * couldn't be loaded
2466 memset(&bm, 0, sizeof(bm));
2467 bm.bmWidth = 32;
2468 bm.bmHeight = 32;
2471 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2472 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2473 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2474 if(FAILED(hr)) {
2475 ERR("Wine logo requested, but failed to create surface\n");
2476 goto out;
2479 if(dcb) {
2480 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2481 if(FAILED(hr)) goto out;
2482 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2483 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2485 colorkey.dwColorSpaceLowValue = 0;
2486 colorkey.dwColorSpaceHighValue = 0;
2487 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2488 } else {
2489 /* Fill the surface with a white color to show that wined3d is there */
2490 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2493 out:
2494 if(dcb) {
2495 DeleteDC(dcb);
2497 if(hbm) {
2498 DeleteObject(hbm);
2500 return;
2503 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2504 unsigned int i;
2505 /* Under DirectX you can have texture stage operations even if no texture is
2506 bound, whereas opengl will only do texture operations when a valid texture is
2507 bound. We emulate this by creating dummy textures and binding them to each
2508 texture stage, but disable all stages by default. Hence if a stage is enabled
2509 then the default texture will kick in until replaced by a SetTexture call */
2510 ENTER_GL();
2512 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2513 /* The dummy texture does not have client storage backing */
2514 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2515 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2517 for (i = 0; i < GL_LIMITS(textures); i++) {
2518 GLubyte white = 255;
2520 /* Make appropriate texture active */
2521 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2522 checkGLcall("glActiveTextureARB");
2524 /* Generate an opengl texture name */
2525 glGenTextures(1, &This->dummyTextureName[i]);
2526 checkGLcall("glGenTextures");
2527 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2529 /* Generate a dummy 2d texture (not using 1d because they cause many
2530 * DRI drivers fall back to sw) */
2531 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2532 checkGLcall("glBindTexture");
2534 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2535 checkGLcall("glTexImage2D");
2537 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2538 /* Reenable because if supported it is enabled by default */
2539 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2540 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2543 LEAVE_GL();
2546 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2547 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2550 IWineD3DSwapChainImpl *swapchain = NULL;
2551 HRESULT hr;
2552 DWORD state;
2553 unsigned int i;
2555 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2557 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2558 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2560 /* TODO: Test if OpenGL is compiled in and loaded */
2562 TRACE("(%p) : Creating stateblock\n", This);
2563 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2564 hr = IWineD3DDevice_CreateStateBlock(iface,
2565 WINED3DSBT_INIT,
2566 (IWineD3DStateBlock **)&This->stateBlock,
2567 NULL);
2568 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2569 WARN("Failed to create stateblock\n");
2570 goto err_out;
2572 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2573 This->updateStateBlock = This->stateBlock;
2574 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2576 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2577 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2579 This->NumberOfPalettes = 1;
2580 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2581 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2582 ERR("Out of memory!\n");
2583 goto err_out;
2585 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2586 if(!This->palettes[0]) {
2587 ERR("Out of memory!\n");
2588 goto err_out;
2590 for (i = 0; i < 256; ++i) {
2591 This->palettes[0][i].peRed = 0xFF;
2592 This->palettes[0][i].peGreen = 0xFF;
2593 This->palettes[0][i].peBlue = 0xFF;
2594 This->palettes[0][i].peFlags = 0xFF;
2596 This->currentPalette = 0;
2598 /* Initialize the texture unit mapping to a 1:1 mapping */
2599 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2600 if (state < GL_LIMITS(fragment_samplers)) {
2601 This->texUnitMap[state] = state;
2602 This->rev_tex_unit_map[state] = state;
2603 } else {
2604 This->texUnitMap[state] = -1;
2605 This->rev_tex_unit_map[state] = -1;
2609 /* Setup the implicit swapchain */
2610 TRACE("Creating implicit swapchain\n");
2611 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2612 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2613 if (FAILED(hr))
2615 WARN("Failed to create implicit swapchain\n");
2616 goto err_out;
2619 This->NumberOfSwapChains = 1;
2620 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2621 if(!This->swapchains) {
2622 ERR("Out of memory!\n");
2623 goto err_out;
2625 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2627 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2628 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2629 This->render_targets[0] = swapchain->backBuffer[0];
2630 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2632 else {
2633 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2634 This->render_targets[0] = swapchain->frontBuffer;
2635 This->lastActiveRenderTarget = swapchain->frontBuffer;
2637 IWineD3DSurface_AddRef(This->render_targets[0]);
2638 This->activeContext = swapchain->context[0];
2639 This->lastThread = GetCurrentThreadId();
2641 /* Depth Stencil support */
2642 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2643 if (NULL != This->stencilBufferTarget) {
2644 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2647 hr = This->shader_backend->shader_alloc_private(iface);
2648 if(FAILED(hr)) {
2649 TRACE("Shader private data couldn't be allocated\n");
2650 goto err_out;
2652 hr = This->frag_pipe->alloc_private(iface);
2653 if(FAILED(hr)) {
2654 TRACE("Fragment pipeline private data couldn't be allocated\n");
2655 goto err_out;
2657 hr = This->blitter->alloc_private(iface);
2658 if(FAILED(hr)) {
2659 TRACE("Blitter private data couldn't be allocated\n");
2660 goto err_out;
2663 /* Set up some starting GL setup */
2665 /* Setup all the devices defaults */
2666 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2667 create_dummy_textures(This);
2669 ENTER_GL();
2671 /* Initialize the current view state */
2672 This->view_ident = 1;
2673 This->contexts[0]->last_was_rhw = 0;
2674 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2675 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2677 switch(wined3d_settings.offscreen_rendering_mode) {
2678 case ORM_FBO:
2679 case ORM_PBUFFER:
2680 This->offscreenBuffer = GL_BACK;
2681 break;
2683 case ORM_BACKBUFFER:
2685 if(This->activeContext->aux_buffers > 0) {
2686 TRACE("Using auxilliary buffer for offscreen rendering\n");
2687 This->offscreenBuffer = GL_AUX0;
2688 } else {
2689 TRACE("Using back buffer for offscreen rendering\n");
2690 This->offscreenBuffer = GL_BACK;
2695 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2696 LEAVE_GL();
2698 /* Clear the screen */
2699 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2700 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2701 0x00, 1.0, 0);
2703 This->d3d_initialized = TRUE;
2705 if(wined3d_settings.logo) {
2706 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2708 This->highest_dirty_ps_const = 0;
2709 This->highest_dirty_vs_const = 0;
2710 return WINED3D_OK;
2712 err_out:
2713 HeapFree(GetProcessHeap(), 0, This->render_targets);
2714 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2715 HeapFree(GetProcessHeap(), 0, This->swapchains);
2716 This->NumberOfSwapChains = 0;
2717 if(This->palettes) {
2718 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2719 HeapFree(GetProcessHeap(), 0, This->palettes);
2721 This->NumberOfPalettes = 0;
2722 if(swapchain) {
2723 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2725 if(This->stateBlock) {
2726 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2727 This->stateBlock = NULL;
2729 if (This->blit_priv) {
2730 This->blitter->free_private(iface);
2732 if (This->fragment_priv) {
2733 This->frag_pipe->free_private(iface);
2735 if (This->shader_priv) {
2736 This->shader_backend->shader_free_private(iface);
2738 return hr;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2742 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2745 IWineD3DSwapChainImpl *swapchain = NULL;
2746 HRESULT hr;
2748 /* Setup the implicit swapchain */
2749 TRACE("Creating implicit swapchain\n");
2750 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2751 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2752 if (FAILED(hr))
2754 WARN("Failed to create implicit swapchain\n");
2755 goto err_out;
2758 This->NumberOfSwapChains = 1;
2759 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2760 if(!This->swapchains) {
2761 ERR("Out of memory!\n");
2762 goto err_out;
2764 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2765 return WINED3D_OK;
2767 err_out:
2768 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2769 return hr;
2772 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2774 IWineD3DResource_UnLoad(resource);
2775 IWineD3DResource_Release(resource);
2776 return WINED3D_OK;
2779 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2781 int sampler;
2782 UINT i;
2783 TRACE("(%p)\n", This);
2785 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2787 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2788 * it was created. Thus make sure a context is active for the glDelete* calls
2790 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2792 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2794 /* Unload resources */
2795 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2797 TRACE("Deleting high order patches\n");
2798 for(i = 0; i < PATCHMAP_SIZE; i++) {
2799 struct list *e1, *e2;
2800 struct WineD3DRectPatch *patch;
2801 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2802 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2803 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2807 /* Delete the palette conversion shader if it is around */
2808 if(This->paletteConversionShader) {
2809 ENTER_GL();
2810 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2811 LEAVE_GL();
2812 This->paletteConversionShader = 0;
2815 /* Delete the pbuffer context if there is any */
2816 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2818 /* Delete the mouse cursor texture */
2819 if(This->cursorTexture) {
2820 ENTER_GL();
2821 glDeleteTextures(1, &This->cursorTexture);
2822 LEAVE_GL();
2823 This->cursorTexture = 0;
2826 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2827 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2829 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2830 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2833 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2834 * private data, it might contain opengl pointers
2836 if(This->depth_blt_texture) {
2837 ENTER_GL();
2838 glDeleteTextures(1, &This->depth_blt_texture);
2839 LEAVE_GL();
2840 This->depth_blt_texture = 0;
2842 if (This->depth_blt_rb) {
2843 ENTER_GL();
2844 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2845 LEAVE_GL();
2846 This->depth_blt_rb = 0;
2847 This->depth_blt_rb_w = 0;
2848 This->depth_blt_rb_h = 0;
2851 /* Release the update stateblock */
2852 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2853 if(This->updateStateBlock != This->stateBlock)
2854 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2856 This->updateStateBlock = NULL;
2858 { /* because were not doing proper internal refcounts releasing the primary state block
2859 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2860 to set this->stateBlock = NULL; first */
2861 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2862 This->stateBlock = NULL;
2864 /* Release the stateblock */
2865 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2866 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2870 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2871 This->blitter->free_private(iface);
2872 This->frag_pipe->free_private(iface);
2873 This->shader_backend->shader_free_private(iface);
2875 /* Release the buffers (with sanity checks)*/
2876 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2877 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2878 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2879 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2881 This->stencilBufferTarget = NULL;
2883 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2884 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2885 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2887 TRACE("Setting rendertarget to NULL\n");
2888 This->render_targets[0] = NULL;
2890 if (This->auto_depth_stencil_buffer) {
2891 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2892 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2894 This->auto_depth_stencil_buffer = NULL;
2897 for(i=0; i < This->NumberOfSwapChains; i++) {
2898 TRACE("Releasing the implicit swapchain %d\n", i);
2899 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2900 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2904 HeapFree(GetProcessHeap(), 0, This->swapchains);
2905 This->swapchains = NULL;
2906 This->NumberOfSwapChains = 0;
2908 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2909 HeapFree(GetProcessHeap(), 0, This->palettes);
2910 This->palettes = NULL;
2911 This->NumberOfPalettes = 0;
2913 HeapFree(GetProcessHeap(), 0, This->render_targets);
2914 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2915 This->render_targets = NULL;
2916 This->draw_buffers = NULL;
2918 This->d3d_initialized = FALSE;
2919 return WINED3D_OK;
2922 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2924 unsigned int i;
2926 for(i=0; i < This->NumberOfSwapChains; i++) {
2927 TRACE("Releasing the implicit swapchain %d\n", i);
2928 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2929 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2933 HeapFree(GetProcessHeap(), 0, This->swapchains);
2934 This->swapchains = NULL;
2935 This->NumberOfSwapChains = 0;
2936 return WINED3D_OK;
2939 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2940 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2941 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2943 * There is no way to deactivate thread safety once it is enabled.
2945 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2948 /*For now just store the flag(needed in case of ddraw) */
2949 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2951 return;
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2955 const WINED3DDISPLAYMODE* pMode) {
2956 DEVMODEW devmode;
2957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 LONG ret;
2959 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2960 RECT clip_rc;
2962 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2964 /* Resize the screen even without a window:
2965 * The app could have unset it with SetCooperativeLevel, but not called
2966 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2967 * but we don't have any hwnd
2970 memset(&devmode, 0, sizeof(devmode));
2971 devmode.dmSize = sizeof(devmode);
2972 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2973 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2974 devmode.dmPelsWidth = pMode->Width;
2975 devmode.dmPelsHeight = pMode->Height;
2977 devmode.dmDisplayFrequency = pMode->RefreshRate;
2978 if (pMode->RefreshRate != 0) {
2979 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2982 /* Only change the mode if necessary */
2983 if( (This->ddraw_width == pMode->Width) &&
2984 (This->ddraw_height == pMode->Height) &&
2985 (This->ddraw_format == pMode->Format) &&
2986 (pMode->RefreshRate == 0) ) {
2987 return WINED3D_OK;
2990 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2991 if (ret != DISP_CHANGE_SUCCESSFUL) {
2992 if(devmode.dmDisplayFrequency != 0) {
2993 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2994 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2995 devmode.dmDisplayFrequency = 0;
2996 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2998 if(ret != DISP_CHANGE_SUCCESSFUL) {
2999 return WINED3DERR_NOTAVAILABLE;
3003 /* Store the new values */
3004 This->ddraw_width = pMode->Width;
3005 This->ddraw_height = pMode->Height;
3006 This->ddraw_format = pMode->Format;
3008 /* And finally clip mouse to our screen */
3009 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3010 ClipCursor(&clip_rc);
3012 return WINED3D_OK;
3015 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 *ppD3D= This->wineD3D;
3018 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3019 IWineD3D_AddRef(*ppD3D);
3020 return WINED3D_OK;
3023 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3027 (This->adapter->TextureRam/(1024*1024)),
3028 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3029 /* return simulated texture memory left */
3030 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3033 /*****
3034 * Get / Set Stream Source
3035 *****/
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3037 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 IWineD3DBuffer *oldSrc;
3042 if (StreamNumber >= MAX_STREAMS) {
3043 WARN("Stream out of range %d\n", StreamNumber);
3044 return WINED3DERR_INVALIDCALL;
3045 } else if(OffsetInBytes & 0x3) {
3046 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3047 return WINED3DERR_INVALIDCALL;
3050 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3051 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3053 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3055 if(oldSrc == pStreamData &&
3056 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3057 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3058 TRACE("Application is setting the old values over, nothing to do\n");
3059 return WINED3D_OK;
3062 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3063 if (pStreamData) {
3064 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3065 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3068 /* Handle recording of state blocks */
3069 if (This->isRecordingState) {
3070 TRACE("Recording... not performing anything\n");
3071 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3072 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3073 return WINED3D_OK;
3076 if (pStreamData != NULL) {
3077 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3078 IWineD3DBuffer_AddRef(pStreamData);
3080 if (oldSrc != NULL) {
3081 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3082 IWineD3DBuffer_Release(oldSrc);
3085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3087 return WINED3D_OK;
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3091 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3095 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3096 This->stateBlock->streamSource[StreamNumber],
3097 This->stateBlock->streamOffset[StreamNumber],
3098 This->stateBlock->streamStride[StreamNumber]);
3100 if (StreamNumber >= MAX_STREAMS) {
3101 WARN("Stream out of range %d\n", StreamNumber);
3102 return WINED3DERR_INVALIDCALL;
3104 *pStream = This->stateBlock->streamSource[StreamNumber];
3105 *pStride = This->stateBlock->streamStride[StreamNumber];
3106 if (pOffset) {
3107 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3110 if (*pStream != NULL) {
3111 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3113 return WINED3D_OK;
3116 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3119 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3121 /* Verify input at least in d3d9 this is invalid*/
3122 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3123 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3124 return WINED3DERR_INVALIDCALL;
3126 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3127 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3128 return WINED3DERR_INVALIDCALL;
3130 if( Divider == 0 ){
3131 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3132 return WINED3DERR_INVALIDCALL;
3135 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3136 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3138 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3139 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3141 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3142 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3153 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3155 TRACE("(%p) : returning %d\n", This, *Divider);
3157 return WINED3D_OK;
3160 /*****
3161 * Get / Set & Multiply Transform
3162 *****/
3163 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 /* Most of this routine, comments included copied from ddraw tree initially: */
3167 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3169 /* Handle recording of state blocks */
3170 if (This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3172 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3173 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3174 return WINED3D_OK;
3178 * If the new matrix is the same as the current one,
3179 * we cut off any further processing. this seems to be a reasonable
3180 * optimization because as was noticed, some apps (warcraft3 for example)
3181 * tend towards setting the same matrix repeatedly for some reason.
3183 * From here on we assume that the new matrix is different, wherever it matters.
3185 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3186 TRACE("The app is setting the same matrix over again\n");
3187 return WINED3D_OK;
3188 } else {
3189 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3193 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3194 where ViewMat = Camera space, WorldMat = world space.
3196 In OpenGL, camera and world space is combined into GL_MODELVIEW
3197 matrix. The Projection matrix stay projection matrix.
3200 /* Capture the times we can just ignore the change for now */
3201 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3202 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3203 /* Handled by the state manager */
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3213 *pMatrix = This->stateBlock->transforms[State];
3214 return WINED3D_OK;
3217 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3218 const WINED3DMATRIX *mat = NULL;
3219 WINED3DMATRIX temp;
3221 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3222 * below means it will be recorded in a state block change, but it
3223 * works regardless where it is recorded.
3224 * If this is found to be wrong, change to StateBlock.
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3229 if (State <= HIGHEST_TRANSFORMSTATE)
3231 mat = &This->updateStateBlock->transforms[State];
3232 } else {
3233 FIXME("Unhandled transform state!!\n");
3236 multiply_matrix(&temp, mat, pMatrix);
3238 /* Apply change via set transform - will reapply to eg. lights this way */
3239 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3242 /*****
3243 * Get / Set Light
3244 *****/
3245 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3246 you can reference any indexes you want as long as that number max are enabled at any
3247 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3248 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3249 but when recording, just build a chain pretty much of commands to be replayed. */
3251 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3252 float rho;
3253 PLIGHTINFOEL *object = NULL;
3254 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3255 struct list *e;
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3260 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3261 * the gl driver.
3263 if(!pLight) {
3264 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3265 return WINED3DERR_INVALIDCALL;
3268 switch(pLight->Type) {
3269 case WINED3DLIGHT_POINT:
3270 case WINED3DLIGHT_SPOT:
3271 case WINED3DLIGHT_PARALLELPOINT:
3272 case WINED3DLIGHT_GLSPOT:
3273 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3274 * most wanted
3276 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3277 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3278 return WINED3DERR_INVALIDCALL;
3280 break;
3282 case WINED3DLIGHT_DIRECTIONAL:
3283 /* Ignores attenuation */
3284 break;
3286 default:
3287 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3288 return WINED3DERR_INVALIDCALL;
3291 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3292 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3293 if(object->OriginalIndex == Index) break;
3294 object = NULL;
3297 if(!object) {
3298 TRACE("Adding new light\n");
3299 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3300 if(!object) {
3301 ERR("Out of memory error when allocating a light\n");
3302 return E_OUTOFMEMORY;
3304 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3305 object->glIndex = -1;
3306 object->OriginalIndex = Index;
3307 object->changed = TRUE;
3310 /* Initialize the object */
3311 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,
3312 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3313 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3314 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3315 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3316 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3317 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3319 /* Save away the information */
3320 object->OriginalParms = *pLight;
3322 switch (pLight->Type) {
3323 case WINED3DLIGHT_POINT:
3324 /* Position */
3325 object->lightPosn[0] = pLight->Position.x;
3326 object->lightPosn[1] = pLight->Position.y;
3327 object->lightPosn[2] = pLight->Position.z;
3328 object->lightPosn[3] = 1.0f;
3329 object->cutoff = 180.0f;
3330 /* FIXME: Range */
3331 break;
3333 case WINED3DLIGHT_DIRECTIONAL:
3334 /* Direction */
3335 object->lightPosn[0] = -pLight->Direction.x;
3336 object->lightPosn[1] = -pLight->Direction.y;
3337 object->lightPosn[2] = -pLight->Direction.z;
3338 object->lightPosn[3] = 0.0;
3339 object->exponent = 0.0f;
3340 object->cutoff = 180.0f;
3341 break;
3343 case WINED3DLIGHT_SPOT:
3344 /* Position */
3345 object->lightPosn[0] = pLight->Position.x;
3346 object->lightPosn[1] = pLight->Position.y;
3347 object->lightPosn[2] = pLight->Position.z;
3348 object->lightPosn[3] = 1.0;
3350 /* Direction */
3351 object->lightDirn[0] = pLight->Direction.x;
3352 object->lightDirn[1] = pLight->Direction.y;
3353 object->lightDirn[2] = pLight->Direction.z;
3354 object->lightDirn[3] = 1.0;
3357 * opengl-ish and d3d-ish spot lights use too different models for the
3358 * light "intensity" as a function of the angle towards the main light direction,
3359 * so we only can approximate very roughly.
3360 * however spot lights are rather rarely used in games (if ever used at all).
3361 * furthermore if still used, probably nobody pays attention to such details.
3363 if (pLight->Falloff == 0) {
3364 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3365 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3366 * will always be 1.0 for both of them, and we don't have to care for the
3367 * rest of the rather complex calculation
3369 object->exponent = 0;
3370 } else {
3371 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3372 if (rho < 0.0001) rho = 0.0001f;
3373 object->exponent = -0.3/log(cos(rho/2));
3375 if (object->exponent > 128.0) {
3376 object->exponent = 128.0;
3378 object->cutoff = pLight->Phi*90/M_PI;
3380 /* FIXME: Range */
3381 break;
3383 default:
3384 FIXME("Unrecognized light type %d\n", pLight->Type);
3387 /* Update the live definitions if the light is currently assigned a glIndex */
3388 if (object->glIndex != -1 && !This->isRecordingState) {
3389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3395 PLIGHTINFOEL *lightInfo = NULL;
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3397 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3398 struct list *e;
3399 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3401 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3402 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3403 if(lightInfo->OriginalIndex == Index) break;
3404 lightInfo = NULL;
3407 if (lightInfo == NULL) {
3408 TRACE("Light information requested but light not defined\n");
3409 return WINED3DERR_INVALIDCALL;
3412 *pLight = lightInfo->OriginalParms;
3413 return WINED3D_OK;
3416 /*****
3417 * Get / Set Light Enable
3418 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3419 *****/
3420 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3421 PLIGHTINFOEL *lightInfo = NULL;
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3424 struct list *e;
3425 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3427 /* Tests show true = 128...not clear why */
3428 Enable = Enable? 128: 0;
3430 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3431 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3432 if(lightInfo->OriginalIndex == Index) break;
3433 lightInfo = NULL;
3435 TRACE("Found light: %p\n", lightInfo);
3437 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3438 if (lightInfo == NULL) {
3440 TRACE("Light enabled requested but light not defined, so defining one!\n");
3441 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3443 /* Search for it again! Should be fairly quick as near head of list */
3444 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3445 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3446 if(lightInfo->OriginalIndex == Index) break;
3447 lightInfo = NULL;
3449 if (lightInfo == NULL) {
3450 FIXME("Adding default lights has failed dismally\n");
3451 return WINED3DERR_INVALIDCALL;
3455 lightInfo->enabledChanged = TRUE;
3456 if(!Enable) {
3457 if(lightInfo->glIndex != -1) {
3458 if(!This->isRecordingState) {
3459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3462 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3463 lightInfo->glIndex = -1;
3464 } else {
3465 TRACE("Light already disabled, nothing to do\n");
3467 lightInfo->enabled = FALSE;
3468 } else {
3469 lightInfo->enabled = TRUE;
3470 if (lightInfo->glIndex != -1) {
3471 /* nop */
3472 TRACE("Nothing to do as light was enabled\n");
3473 } else {
3474 int i;
3475 /* Find a free gl light */
3476 for(i = 0; i < This->maxConcurrentLights; i++) {
3477 if(This->updateStateBlock->activeLights[i] == NULL) {
3478 This->updateStateBlock->activeLights[i] = lightInfo;
3479 lightInfo->glIndex = i;
3480 break;
3483 if(lightInfo->glIndex == -1) {
3484 /* Our tests show that Windows returns D3D_OK in this situation, even with
3485 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3486 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3487 * as well for those lights.
3489 * TODO: Test how this affects rendering
3491 WARN("Too many concurrently active lights\n");
3492 return WINED3D_OK;
3495 /* i == lightInfo->glIndex */
3496 if(!This->isRecordingState) {
3497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3502 return WINED3D_OK;
3505 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3507 PLIGHTINFOEL *lightInfo = NULL;
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 struct list *e;
3510 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3511 TRACE("(%p) : for idx(%d)\n", This, Index);
3513 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3514 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3515 if(lightInfo->OriginalIndex == Index) break;
3516 lightInfo = NULL;
3519 if (lightInfo == NULL) {
3520 TRACE("Light enabled state requested but light not defined\n");
3521 return WINED3DERR_INVALIDCALL;
3523 /* true is 128 according to SetLightEnable */
3524 *pEnable = lightInfo->enabled ? 128 : 0;
3525 return WINED3D_OK;
3528 /*****
3529 * Get / Set Clip Planes
3530 *****/
3531 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3535 /* Validate Index */
3536 if (Index >= GL_LIMITS(clipplanes)) {
3537 TRACE("Application has requested clipplane this device doesn't support\n");
3538 return WINED3DERR_INVALIDCALL;
3541 This->updateStateBlock->changed.clipplane |= 1 << Index;
3543 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3544 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3545 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3546 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3547 TRACE("Application is setting old values over, nothing to do\n");
3548 return WINED3D_OK;
3551 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3552 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3553 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3554 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3556 /* Handle recording of state blocks */
3557 if (This->isRecordingState) {
3558 TRACE("Recording... not performing anything\n");
3559 return WINED3D_OK;
3562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3564 return WINED3D_OK;
3567 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3569 TRACE("(%p) : for idx %d\n", This, Index);
3571 /* Validate Index */
3572 if (Index >= GL_LIMITS(clipplanes)) {
3573 TRACE("Application has requested clipplane this device doesn't support\n");
3574 return WINED3DERR_INVALIDCALL;
3577 pPlane[0] = This->stateBlock->clipplane[Index][0];
3578 pPlane[1] = This->stateBlock->clipplane[Index][1];
3579 pPlane[2] = This->stateBlock->clipplane[Index][2];
3580 pPlane[3] = This->stateBlock->clipplane[Index][3];
3581 return WINED3D_OK;
3584 /*****
3585 * Get / Set Clip Plane Status
3586 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3587 *****/
3588 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3590 FIXME("(%p) : stub\n", This);
3591 if (NULL == pClipStatus) {
3592 return WINED3DERR_INVALIDCALL;
3594 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3595 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3596 return WINED3D_OK;
3599 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3601 FIXME("(%p) : stub\n", This);
3602 if (NULL == pClipStatus) {
3603 return WINED3DERR_INVALIDCALL;
3605 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3606 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3607 return WINED3D_OK;
3610 /*****
3611 * Get / Set Material
3612 *****/
3613 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3616 This->updateStateBlock->changed.material = TRUE;
3617 This->updateStateBlock->material = *pMaterial;
3619 /* Handle recording of state blocks */
3620 if (This->isRecordingState) {
3621 TRACE("Recording... not performing anything\n");
3622 return WINED3D_OK;
3625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3626 return WINED3D_OK;
3629 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3631 *pMaterial = This->updateStateBlock->material;
3632 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3633 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3634 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3635 pMaterial->Ambient.b, pMaterial->Ambient.a);
3636 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3637 pMaterial->Specular.b, pMaterial->Specular.a);
3638 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3639 pMaterial->Emissive.b, pMaterial->Emissive.a);
3640 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3642 return WINED3D_OK;
3645 /*****
3646 * Get / Set Indices
3647 *****/
3648 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3650 IWineD3DBuffer *oldIdxs;
3652 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3653 oldIdxs = This->updateStateBlock->pIndexData;
3655 This->updateStateBlock->changed.indices = TRUE;
3656 This->updateStateBlock->pIndexData = pIndexData;
3657 This->updateStateBlock->IndexFmt = fmt;
3659 /* Handle recording of state blocks */
3660 if (This->isRecordingState) {
3661 TRACE("Recording... not performing anything\n");
3662 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3663 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3664 return WINED3D_OK;
3667 if(oldIdxs != pIndexData) {
3668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3669 if(pIndexData) {
3670 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3671 IWineD3DBuffer_AddRef(pIndexData);
3673 if(oldIdxs) {
3674 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3675 IWineD3DBuffer_Release(oldIdxs);
3679 return WINED3D_OK;
3682 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3685 *ppIndexData = This->stateBlock->pIndexData;
3687 /* up ref count on ppindexdata */
3688 if (*ppIndexData) {
3689 IWineD3DBuffer_AddRef(*ppIndexData);
3690 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3691 }else{
3692 TRACE("(%p) No index data set\n", This);
3694 TRACE("Returning %p\n", *ppIndexData);
3696 return WINED3D_OK;
3699 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3700 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3702 TRACE("(%p)->(%d)\n", This, BaseIndex);
3704 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3705 TRACE("Application is setting the old value over, nothing to do\n");
3706 return WINED3D_OK;
3709 This->updateStateBlock->baseVertexIndex = BaseIndex;
3711 if (This->isRecordingState) {
3712 TRACE("Recording... not performing anything\n");
3713 return WINED3D_OK;
3715 /* The base vertex index affects the stream sources */
3716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3717 return WINED3D_OK;
3720 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3722 TRACE("(%p) : base_index %p\n", This, base_index);
3724 *base_index = This->stateBlock->baseVertexIndex;
3726 TRACE("Returning %u\n", *base_index);
3728 return WINED3D_OK;
3731 /*****
3732 * Get / Set Viewports
3733 *****/
3734 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3737 TRACE("(%p)\n", This);
3738 This->updateStateBlock->changed.viewport = TRUE;
3739 This->updateStateBlock->viewport = *pViewport;
3741 /* Handle recording of state blocks */
3742 if (This->isRecordingState) {
3743 TRACE("Recording... not performing anything\n");
3744 return WINED3D_OK;
3747 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3748 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3751 return WINED3D_OK;
3755 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 TRACE("(%p)\n", This);
3758 *pViewport = This->stateBlock->viewport;
3759 return WINED3D_OK;
3762 /*****
3763 * Get / Set Render States
3764 * TODO: Verify against dx9 definitions
3765 *****/
3766 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3769 DWORD oldValue = This->stateBlock->renderState[State];
3771 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3773 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3774 This->updateStateBlock->renderState[State] = Value;
3776 /* Handle recording of state blocks */
3777 if (This->isRecordingState) {
3778 TRACE("Recording... not performing anything\n");
3779 return WINED3D_OK;
3782 /* Compared here and not before the assignment to allow proper stateblock recording */
3783 if(Value == oldValue) {
3784 TRACE("Application is setting the old value over, nothing to do\n");
3785 } else {
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3789 return WINED3D_OK;
3792 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3795 *pValue = This->stateBlock->renderState[State];
3796 return WINED3D_OK;
3799 /*****
3800 * Get / Set Sampler States
3801 * TODO: Verify against dx9 definitions
3802 *****/
3804 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 DWORD oldValue;
3808 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3809 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3811 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3812 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3815 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3816 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3817 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3820 * SetSampler is designed to allow for more than the standard up to 8 textures
3821 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3822 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3824 * http://developer.nvidia.com/object/General_FAQ.html#t6
3826 * There are two new settings for GForce
3827 * the sampler one:
3828 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3829 * and the texture one:
3830 * GL_MAX_TEXTURE_COORDS_ARB.
3831 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3832 ******************/
3834 oldValue = This->stateBlock->samplerState[Sampler][Type];
3835 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3836 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3838 /* Handle recording of state blocks */
3839 if (This->isRecordingState) {
3840 TRACE("Recording... not performing anything\n");
3841 return WINED3D_OK;
3844 if(oldValue == Value) {
3845 TRACE("Application is setting the old value over, nothing to do\n");
3846 return WINED3D_OK;
3849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3851 return WINED3D_OK;
3854 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3857 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3858 This, Sampler, debug_d3dsamplerstate(Type), Type);
3860 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3861 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3864 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3865 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3866 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3868 *Value = This->stateBlock->samplerState[Sampler][Type];
3869 TRACE("(%p) : Returning %#x\n", This, *Value);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 This->updateStateBlock->changed.scissorRect = TRUE;
3878 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3879 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3880 return WINED3D_OK;
3882 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3884 if(This->isRecordingState) {
3885 TRACE("Recording... not performing anything\n");
3886 return WINED3D_OK;
3889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3891 return WINED3D_OK;
3894 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 *pRect = This->updateStateBlock->scissorRect;
3898 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3899 return WINED3D_OK;
3902 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3904 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3906 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3908 This->updateStateBlock->vertexDecl = pDecl;
3909 This->updateStateBlock->changed.vertexDecl = TRUE;
3911 if (This->isRecordingState) {
3912 TRACE("Recording... not performing anything\n");
3913 return WINED3D_OK;
3914 } else if(pDecl == oldDecl) {
3915 /* Checked after the assignment to allow proper stateblock recording */
3916 TRACE("Application is setting the old declaration over, nothing to do\n");
3917 return WINED3D_OK;
3920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3921 return WINED3D_OK;
3924 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3927 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3929 *ppDecl = This->stateBlock->vertexDecl;
3930 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3931 return WINED3D_OK;
3934 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3936 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3938 This->updateStateBlock->vertexShader = pShader;
3939 This->updateStateBlock->changed.vertexShader = TRUE;
3941 if (This->isRecordingState) {
3942 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3943 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3944 TRACE("Recording... not performing anything\n");
3945 return WINED3D_OK;
3946 } else if(oldShader == pShader) {
3947 /* Checked here to allow proper stateblock recording */
3948 TRACE("App is setting the old shader over, nothing to do\n");
3949 return WINED3D_OK;
3952 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3953 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3954 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3958 return WINED3D_OK;
3961 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3964 if (NULL == ppShader) {
3965 return WINED3DERR_INVALIDCALL;
3967 *ppShader = This->stateBlock->vertexShader;
3968 if( NULL != *ppShader)
3969 IWineD3DVertexShader_AddRef(*ppShader);
3971 TRACE("(%p) : returning %p\n", This, *ppShader);
3972 return WINED3D_OK;
3975 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3976 IWineD3DDevice *iface,
3977 UINT start,
3978 CONST BOOL *srcData,
3979 UINT count) {
3981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3982 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3984 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3985 iface, srcData, start, count);
3987 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3989 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3990 for (i = 0; i < cnt; i++)
3991 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3993 for (i = start; i < cnt + start; ++i) {
3994 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3997 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3999 return WINED3D_OK;
4002 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4003 IWineD3DDevice *iface,
4004 UINT start,
4005 BOOL *dstData,
4006 UINT count) {
4008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4009 int cnt = min(count, MAX_CONST_B - start);
4011 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4012 iface, dstData, start, count);
4014 if (dstData == NULL || cnt < 0)
4015 return WINED3DERR_INVALIDCALL;
4017 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4018 return WINED3D_OK;
4021 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4022 IWineD3DDevice *iface,
4023 UINT start,
4024 CONST int *srcData,
4025 UINT count) {
4027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4028 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4030 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4031 iface, srcData, start, count);
4033 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4035 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4036 for (i = 0; i < cnt; i++)
4037 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4038 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4040 for (i = start; i < cnt + start; ++i) {
4041 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4044 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4046 return WINED3D_OK;
4049 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4050 IWineD3DDevice *iface,
4051 UINT start,
4052 int *dstData,
4053 UINT count) {
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4056 int cnt = min(count, MAX_CONST_I - start);
4058 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4059 iface, dstData, start, count);
4061 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4062 return WINED3DERR_INVALIDCALL;
4064 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4065 return WINED3D_OK;
4068 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4069 IWineD3DDevice *iface,
4070 UINT start,
4071 CONST float *srcData,
4072 UINT count) {
4074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4075 UINT i;
4077 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4078 iface, srcData, start, count);
4080 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4081 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
4082 return WINED3DERR_INVALIDCALL;
4084 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4085 if(TRACE_ON(d3d)) {
4086 for (i = 0; i < count; i++)
4087 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4088 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4091 if (!This->isRecordingState)
4093 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4097 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4098 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4100 return WINED3D_OK;
4103 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4104 IWineD3DDevice *iface,
4105 UINT start,
4106 float *dstData,
4107 UINT count) {
4109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4110 int cnt = min(count, This->d3d_vshader_constantF - start);
4112 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4113 iface, dstData, start, count);
4115 if (dstData == NULL || cnt < 0)
4116 return WINED3DERR_INVALIDCALL;
4118 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4119 return WINED3D_OK;
4122 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4123 DWORD i;
4124 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4130 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4131 int i = This->rev_tex_unit_map[unit];
4132 int j = This->texUnitMap[stage];
4134 This->texUnitMap[stage] = unit;
4135 if (i != -1 && i != stage) {
4136 This->texUnitMap[i] = -1;
4139 This->rev_tex_unit_map[unit] = stage;
4140 if (j != -1 && j != unit) {
4141 This->rev_tex_unit_map[j] = -1;
4145 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4146 int i;
4148 This->fixed_function_usage_map = 0;
4149 for (i = 0; i < MAX_TEXTURES; ++i) {
4150 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4151 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4152 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4153 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4154 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4155 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4156 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4157 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4159 if (color_op == WINED3DTOP_DISABLE) {
4160 /* Not used, and disable higher stages */
4161 break;
4164 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4165 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4166 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4167 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4168 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4169 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4170 This->fixed_function_usage_map |= (1 << i);
4173 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4174 This->fixed_function_usage_map |= (1 << (i + 1));
4179 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4180 unsigned int i, tex;
4181 WORD ffu_map;
4183 device_update_fixed_function_usage_map(This);
4184 ffu_map = This->fixed_function_usage_map;
4186 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4187 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4188 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4190 if (!(ffu_map & 1)) continue;
4192 if (This->texUnitMap[i] != i) {
4193 device_map_stage(This, i, i);
4194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4195 markTextureStagesDirty(This, i);
4198 return;
4201 /* Now work out the mapping */
4202 tex = 0;
4203 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4205 if (!(ffu_map & 1)) continue;
4207 if (This->texUnitMap[i] != tex) {
4208 device_map_stage(This, i, tex);
4209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4210 markTextureStagesDirty(This, i);
4213 ++tex;
4217 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4218 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
4219 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
4220 unsigned int i;
4222 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4223 if (sampler_type[i] && This->texUnitMap[i] != i)
4225 device_map_stage(This, i, i);
4226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4227 if (i < MAX_TEXTURES) {
4228 markTextureStagesDirty(This, i);
4234 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4235 const DWORD *vshader_sampler_tokens, int unit)
4237 int current_mapping = This->rev_tex_unit_map[unit];
4239 if (current_mapping == -1) {
4240 /* Not currently used */
4241 return TRUE;
4244 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4245 /* Used by a fragment sampler */
4247 if (!pshader_sampler_tokens) {
4248 /* No pixel shader, check fixed function */
4249 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4252 /* Pixel shader, check the shader's sampler map */
4253 return !pshader_sampler_tokens[current_mapping];
4256 /* Used by a vertex sampler */
4257 return !vshader_sampler_tokens[current_mapping];
4260 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4261 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
4262 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
4263 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
4264 int start = GL_LIMITS(combined_samplers) - 1;
4265 int i;
4267 if (ps) {
4268 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4270 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4271 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4272 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4275 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4276 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4277 if (vshader_sampler_type[i])
4279 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4281 /* Already mapped somewhere */
4282 continue;
4285 while (start >= 0) {
4286 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4288 device_map_stage(This, vsampler_idx, start);
4289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4291 --start;
4292 break;
4295 --start;
4301 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4302 BOOL vs = use_vs(This->stateBlock);
4303 BOOL ps = use_ps(This->stateBlock);
4305 * Rules are:
4306 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4307 * that would be really messy and require shader recompilation
4308 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4309 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4311 if (ps) {
4312 device_map_psamplers(This);
4313 } else {
4314 device_map_fixed_function_samplers(This);
4317 if (vs) {
4318 device_map_vsamplers(This, ps);
4322 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4325 This->updateStateBlock->pixelShader = pShader;
4326 This->updateStateBlock->changed.pixelShader = TRUE;
4328 /* Handle recording of state blocks */
4329 if (This->isRecordingState) {
4330 TRACE("Recording... not performing anything\n");
4333 if (This->isRecordingState) {
4334 TRACE("Recording... not performing anything\n");
4335 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4336 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4337 return WINED3D_OK;
4340 if(pShader == oldShader) {
4341 TRACE("App is setting the old pixel shader over, nothing to do\n");
4342 return WINED3D_OK;
4345 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4346 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4348 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4351 return WINED3D_OK;
4354 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4357 if (NULL == ppShader) {
4358 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4359 return WINED3DERR_INVALIDCALL;
4362 *ppShader = This->stateBlock->pixelShader;
4363 if (NULL != *ppShader) {
4364 IWineD3DPixelShader_AddRef(*ppShader);
4366 TRACE("(%p) : returning %p\n", This, *ppShader);
4367 return WINED3D_OK;
4370 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4371 IWineD3DDevice *iface,
4372 UINT start,
4373 CONST BOOL *srcData,
4374 UINT count) {
4376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4377 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4379 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4380 iface, srcData, start, count);
4382 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4384 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4385 for (i = 0; i < cnt; i++)
4386 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4388 for (i = start; i < cnt + start; ++i) {
4389 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4392 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4394 return WINED3D_OK;
4397 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4398 IWineD3DDevice *iface,
4399 UINT start,
4400 BOOL *dstData,
4401 UINT count) {
4403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4404 int cnt = min(count, MAX_CONST_B - start);
4406 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4407 iface, dstData, start, count);
4409 if (dstData == NULL || cnt < 0)
4410 return WINED3DERR_INVALIDCALL;
4412 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4413 return WINED3D_OK;
4416 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4417 IWineD3DDevice *iface,
4418 UINT start,
4419 CONST int *srcData,
4420 UINT count) {
4422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4423 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4425 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4426 iface, srcData, start, count);
4428 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4430 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4431 for (i = 0; i < cnt; i++)
4432 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4433 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4435 for (i = start; i < cnt + start; ++i) {
4436 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4439 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4441 return WINED3D_OK;
4444 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4445 IWineD3DDevice *iface,
4446 UINT start,
4447 int *dstData,
4448 UINT count) {
4450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 int cnt = min(count, MAX_CONST_I - start);
4453 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4454 iface, dstData, start, count);
4456 if (dstData == NULL || cnt < 0)
4457 return WINED3DERR_INVALIDCALL;
4459 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4460 return WINED3D_OK;
4463 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4464 IWineD3DDevice *iface,
4465 UINT start,
4466 CONST float *srcData,
4467 UINT count) {
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 UINT i;
4472 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4473 iface, srcData, start, count);
4475 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4476 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4477 return WINED3DERR_INVALIDCALL;
4479 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4480 if(TRACE_ON(d3d)) {
4481 for (i = 0; i < count; i++)
4482 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4483 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4486 if (!This->isRecordingState)
4488 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4492 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4493 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4495 return WINED3D_OK;
4498 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4499 IWineD3DDevice *iface,
4500 UINT start,
4501 float *dstData,
4502 UINT count) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 int cnt = min(count, This->d3d_pshader_constantF - start);
4507 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4508 iface, dstData, start, count);
4510 if (dstData == NULL || cnt < 0)
4511 return WINED3DERR_INVALIDCALL;
4513 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4514 return WINED3D_OK;
4517 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4518 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4519 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4520 DWORD DestFVF)
4522 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4523 unsigned int i;
4524 WINED3DVIEWPORT vp;
4525 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4526 BOOL doClip;
4527 DWORD numTextures;
4529 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4531 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4534 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4536 ERR("Source has no position mask\n");
4537 return WINED3DERR_INVALIDCALL;
4540 /* We might access VBOs from this code, so hold the lock */
4541 ENTER_GL();
4543 if (dest->resource.allocatedMemory == NULL) {
4544 buffer_get_sysmem(dest);
4547 /* Get a pointer into the destination vbo(create one if none exists) and
4548 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4550 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4552 dest->flags |= WINED3D_BUFFER_CREATEBO;
4553 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4556 if (dest->buffer_object)
4558 unsigned char extrabytes = 0;
4559 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4560 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4561 * this may write 4 extra bytes beyond the area that should be written
4563 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4564 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4565 if(!dest_conv_addr) {
4566 ERR("Out of memory\n");
4567 /* Continue without storing converted vertices */
4569 dest_conv = dest_conv_addr;
4572 /* Should I clip?
4573 * a) WINED3DRS_CLIPPING is enabled
4574 * b) WINED3DVOP_CLIP is passed
4576 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4577 static BOOL warned = FALSE;
4579 * The clipping code is not quite correct. Some things need
4580 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4581 * so disable clipping for now.
4582 * (The graphics in Half-Life are broken, and my processvertices
4583 * test crashes with IDirect3DDevice3)
4584 doClip = TRUE;
4586 doClip = FALSE;
4587 if(!warned) {
4588 warned = TRUE;
4589 FIXME("Clipping is broken and disabled for now\n");
4591 } else doClip = FALSE;
4592 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4594 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4595 WINED3DTS_VIEW,
4596 &view_mat);
4597 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4598 WINED3DTS_PROJECTION,
4599 &proj_mat);
4600 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4601 WINED3DTS_WORLDMATRIX(0),
4602 &world_mat);
4604 TRACE("View mat:\n");
4605 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);
4606 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);
4607 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);
4608 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);
4610 TRACE("Proj mat:\n");
4611 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);
4612 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);
4613 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);
4614 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);
4616 TRACE("World mat:\n");
4617 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);
4618 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);
4619 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);
4620 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);
4622 /* Get the viewport */
4623 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4624 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4625 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4627 multiply_matrix(&mat,&view_mat,&world_mat);
4628 multiply_matrix(&mat,&proj_mat,&mat);
4630 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4632 for (i = 0; i < dwCount; i+= 1) {
4633 unsigned int tex_index;
4635 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4636 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4637 /* The position first */
4638 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4639 const float *p = (const float *)(element->data + i * element->stride);
4640 float x, y, z, rhw;
4641 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4643 /* Multiplication with world, view and projection matrix */
4644 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
4645 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
4646 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
4647 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
4649 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4651 /* WARNING: The following things are taken from d3d7 and were not yet checked
4652 * against d3d8 or d3d9!
4655 /* Clipping conditions: From msdn
4657 * A vertex is clipped if it does not match the following requirements
4658 * -rhw < x <= rhw
4659 * -rhw < y <= rhw
4660 * 0 < z <= rhw
4661 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4663 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4664 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4668 if( !doClip ||
4669 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4670 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4671 ( rhw > eps ) ) ) {
4673 /* "Normal" viewport transformation (not clipped)
4674 * 1) The values are divided by rhw
4675 * 2) The y axis is negative, so multiply it with -1
4676 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4677 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4678 * 4) Multiply x with Width/2 and add Width/2
4679 * 5) The same for the height
4680 * 6) Add the viewpoint X and Y to the 2D coordinates and
4681 * The minimum Z value to z
4682 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4684 * Well, basically it's simply a linear transformation into viewport
4685 * coordinates
4688 x /= rhw;
4689 y /= rhw;
4690 z /= rhw;
4692 y *= -1;
4694 x *= vp.Width / 2;
4695 y *= vp.Height / 2;
4696 z *= vp.MaxZ - vp.MinZ;
4698 x += vp.Width / 2 + vp.X;
4699 y += vp.Height / 2 + vp.Y;
4700 z += vp.MinZ;
4702 rhw = 1 / rhw;
4703 } else {
4704 /* That vertex got clipped
4705 * Contrary to OpenGL it is not dropped completely, it just
4706 * undergoes a different calculation.
4708 TRACE("Vertex got clipped\n");
4709 x += rhw;
4710 y += rhw;
4712 x /= 2;
4713 y /= 2;
4715 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4716 * outside of the main vertex buffer memory. That needs some more
4717 * investigation...
4721 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4724 ( (float *) dest_ptr)[0] = x;
4725 ( (float *) dest_ptr)[1] = y;
4726 ( (float *) dest_ptr)[2] = z;
4727 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4729 dest_ptr += 3 * sizeof(float);
4731 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4732 dest_ptr += sizeof(float);
4735 if(dest_conv) {
4736 float w = 1 / rhw;
4737 ( (float *) dest_conv)[0] = x * w;
4738 ( (float *) dest_conv)[1] = y * w;
4739 ( (float *) dest_conv)[2] = z * w;
4740 ( (float *) dest_conv)[3] = w;
4742 dest_conv += 3 * sizeof(float);
4744 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4745 dest_conv += sizeof(float);
4749 if (DestFVF & WINED3DFVF_PSIZE) {
4750 dest_ptr += sizeof(DWORD);
4751 if(dest_conv) dest_conv += sizeof(DWORD);
4753 if (DestFVF & WINED3DFVF_NORMAL) {
4754 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4755 const float *normal = (const float *)(element->data + i * element->stride);
4756 /* AFAIK this should go into the lighting information */
4757 FIXME("Didn't expect the destination to have a normal\n");
4758 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4759 if(dest_conv) {
4760 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4764 if (DestFVF & WINED3DFVF_DIFFUSE) {
4765 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4766 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4767 if(!color_d) {
4768 static BOOL warned = FALSE;
4770 if(!warned) {
4771 ERR("No diffuse color in source, but destination has one\n");
4772 warned = TRUE;
4775 *( (DWORD *) dest_ptr) = 0xffffffff;
4776 dest_ptr += sizeof(DWORD);
4778 if(dest_conv) {
4779 *( (DWORD *) dest_conv) = 0xffffffff;
4780 dest_conv += sizeof(DWORD);
4783 else {
4784 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4785 if(dest_conv) {
4786 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4787 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4788 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4789 dest_conv += sizeof(DWORD);
4794 if (DestFVF & WINED3DFVF_SPECULAR) {
4795 /* What's the color value in the feedback buffer? */
4796 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4797 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4798 if(!color_s) {
4799 static BOOL warned = FALSE;
4801 if(!warned) {
4802 ERR("No specular color in source, but destination has one\n");
4803 warned = TRUE;
4806 *( (DWORD *) dest_ptr) = 0xFF000000;
4807 dest_ptr += sizeof(DWORD);
4809 if(dest_conv) {
4810 *( (DWORD *) dest_conv) = 0xFF000000;
4811 dest_conv += sizeof(DWORD);
4814 else {
4815 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4816 if(dest_conv) {
4817 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4818 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4819 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4820 dest_conv += sizeof(DWORD);
4825 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4826 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4827 const float *tex_coord = (const float *)(element->data + i * element->stride);
4828 if(!tex_coord) {
4829 ERR("No source texture, but destination requests one\n");
4830 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4831 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4833 else {
4834 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4835 if(dest_conv) {
4836 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4842 if(dest_conv) {
4843 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4844 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4845 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4846 dwCount * get_flexible_vertex_size(DestFVF),
4847 dest_conv_addr));
4848 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4849 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4852 LEAVE_GL();
4854 return WINED3D_OK;
4856 #undef copy_and_next
4858 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4859 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4860 DWORD DestFVF)
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4863 struct wined3d_stream_info stream_info;
4864 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4865 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4867 if(pVertexDecl) {
4868 ERR("Output vertex declaration not implemented yet\n");
4871 /* Need any context to write to the vbo. */
4872 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4874 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4875 * control the streamIsUP flag, thus restore it afterwards.
4877 This->stateBlock->streamIsUP = FALSE;
4878 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4879 This->stateBlock->streamIsUP = streamWasUP;
4881 if(vbo || SrcStartIndex) {
4882 unsigned int i;
4883 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4884 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4886 * Also get the start index in, but only loop over all elements if there's something to add at all.
4888 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4890 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4891 if (e->buffer_object)
4893 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4894 e->buffer_object = 0;
4895 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4896 ENTER_GL();
4897 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4898 vb->buffer_object = 0;
4899 LEAVE_GL();
4901 if (e->data) e->data += e->stride * SrcStartIndex;
4905 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4906 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4909 /*****
4910 * Get / Set Texture Stage States
4911 * TODO: Verify against dx9 definitions
4912 *****/
4913 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4917 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4919 if (Stage >= MAX_TEXTURES) {
4920 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4921 return WINED3D_OK;
4924 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4925 This->updateStateBlock->textureState[Stage][Type] = Value;
4927 if (This->isRecordingState) {
4928 TRACE("Recording... not performing anything\n");
4929 return WINED3D_OK;
4932 /* Checked after the assignments to allow proper stateblock recording */
4933 if(oldValue == Value) {
4934 TRACE("App is setting the old value over, nothing to do\n");
4935 return WINED3D_OK;
4938 if(Stage > This->stateBlock->lowest_disabled_stage &&
4939 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4940 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4941 * Changes in other states are important on disabled stages too
4943 return WINED3D_OK;
4946 if(Type == WINED3DTSS_COLOROP) {
4947 unsigned int i;
4949 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4950 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4951 * they have to be disabled
4953 * The current stage is dirtified below.
4955 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4956 TRACE("Additionally dirtifying stage %u\n", i);
4957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4959 This->stateBlock->lowest_disabled_stage = Stage;
4960 TRACE("New lowest disabled: %u\n", Stage);
4961 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4962 /* Previously disabled stage enabled. Stages above it may need enabling
4963 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4964 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4966 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4969 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4970 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4971 break;
4973 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4976 This->stateBlock->lowest_disabled_stage = i;
4977 TRACE("New lowest disabled: %u\n", i);
4981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4983 return WINED3D_OK;
4986 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4989 *pValue = This->updateStateBlock->textureState[Stage][Type];
4990 return WINED3D_OK;
4993 /*****
4994 * Get / Set Texture
4995 *****/
4996 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 IWineD3DBaseTexture *oldTexture;
5000 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
5002 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5003 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5006 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5007 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5008 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5011 oldTexture = This->updateStateBlock->textures[Stage];
5013 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5014 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5016 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5017 return WINED3DERR_INVALIDCALL;
5020 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5021 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5023 This->updateStateBlock->changed.textures |= 1 << Stage;
5024 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5025 This->updateStateBlock->textures[Stage] = pTexture;
5027 /* Handle recording of state blocks */
5028 if (This->isRecordingState) {
5029 TRACE("Recording... not performing anything\n");
5030 return WINED3D_OK;
5033 if(oldTexture == pTexture) {
5034 TRACE("App is setting the same texture again, nothing to do\n");
5035 return WINED3D_OK;
5038 /** NOTE: MSDN says that setTexture increases the reference count,
5039 * and that the application must set the texture back to null (or have a leaky application),
5040 * This means we should pass the refcount up to the parent
5041 *******************************/
5042 if (NULL != This->updateStateBlock->textures[Stage]) {
5043 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5044 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5045 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5047 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5049 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5054 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5055 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5056 * so the COLOROP and ALPHAOP have to be dirtified.
5058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5061 if(bindCount == 1) {
5062 new->baseTexture.sampler = Stage;
5064 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5068 if (NULL != oldTexture) {
5069 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5070 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5072 IWineD3DBaseTexture_Release(oldTexture);
5073 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5078 if(bindCount && old->baseTexture.sampler == Stage) {
5079 int i;
5080 /* Have to do a search for the other sampler(s) where the texture is bound to
5081 * Shouldn't happen as long as apps bind a texture only to one stage
5083 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5084 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5085 if(This->updateStateBlock->textures[i] == oldTexture) {
5086 old->baseTexture.sampler = i;
5087 break;
5093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5095 return WINED3D_OK;
5098 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5101 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5103 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5104 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5107 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5108 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5109 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5112 *ppTexture=This->stateBlock->textures[Stage];
5113 if (*ppTexture)
5114 IWineD3DBaseTexture_AddRef(*ppTexture);
5116 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5118 return WINED3D_OK;
5121 /*****
5122 * Get Back Buffer
5123 *****/
5124 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5125 IWineD3DSurface **ppBackBuffer) {
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5127 IWineD3DSwapChain *swapChain;
5128 HRESULT hr;
5130 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5132 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5133 if (hr == WINED3D_OK) {
5134 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5135 IWineD3DSwapChain_Release(swapChain);
5136 } else {
5137 *ppBackBuffer = NULL;
5139 return hr;
5142 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5144 WARN("(%p) : stub, calling idirect3d for now\n", This);
5145 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5148 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5150 IWineD3DSwapChain *swapChain;
5151 HRESULT hr;
5153 if(iSwapChain > 0) {
5154 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5155 if (hr == WINED3D_OK) {
5156 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5157 IWineD3DSwapChain_Release(swapChain);
5158 } else {
5159 FIXME("(%p) Error getting display mode\n", This);
5161 } else {
5162 /* Don't read the real display mode,
5163 but return the stored mode instead. X11 can't change the color
5164 depth, and some apps are pretty angry if they SetDisplayMode from
5165 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5167 Also don't relay to the swapchain because with ddraw it's possible
5168 that there isn't a swapchain at all */
5169 pMode->Width = This->ddraw_width;
5170 pMode->Height = This->ddraw_height;
5171 pMode->Format = This->ddraw_format;
5172 pMode->RefreshRate = 0;
5173 hr = WINED3D_OK;
5176 return hr;
5179 /*****
5180 * Stateblock related functions
5181 *****/
5183 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5185 IWineD3DStateBlock *stateblock;
5186 HRESULT hr;
5188 TRACE("(%p)\n", This);
5190 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5192 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5193 if (FAILED(hr)) return hr;
5195 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5196 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5197 This->isRecordingState = TRUE;
5199 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5201 return WINED3D_OK;
5204 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 unsigned int i, j;
5207 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5209 if (!This->isRecordingState) {
5210 WARN("(%p) not recording! returning error\n", This);
5211 *ppStateBlock = NULL;
5212 return WINED3DERR_INVALIDCALL;
5215 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5217 DWORD map = object->changed.renderState[i];
5218 for (j = 0; map; map >>= 1, ++j)
5220 if (!(map & 1)) continue;
5222 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5226 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5228 DWORD map = object->changed.transform[i];
5229 for (j = 0; map; map >>= 1, ++j)
5231 if (!(map & 1)) continue;
5233 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5236 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5237 if(object->changed.vertexShaderConstantsF[i]) {
5238 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5239 object->num_contained_vs_consts_f++;
5242 for(i = 0; i < MAX_CONST_I; i++) {
5243 if (object->changed.vertexShaderConstantsI & (1 << i))
5245 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5246 object->num_contained_vs_consts_i++;
5249 for(i = 0; i < MAX_CONST_B; i++) {
5250 if (object->changed.vertexShaderConstantsB & (1 << i))
5252 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5253 object->num_contained_vs_consts_b++;
5256 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5258 if (object->changed.pixelShaderConstantsF[i])
5260 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5261 ++object->num_contained_ps_consts_f;
5264 for(i = 0; i < MAX_CONST_I; i++) {
5265 if (object->changed.pixelShaderConstantsI & (1 << i))
5267 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5268 object->num_contained_ps_consts_i++;
5271 for(i = 0; i < MAX_CONST_B; i++) {
5272 if (object->changed.pixelShaderConstantsB & (1 << i))
5274 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5275 object->num_contained_ps_consts_b++;
5278 for(i = 0; i < MAX_TEXTURES; i++) {
5279 DWORD map = object->changed.textureState[i];
5281 for(j = 0; map; map >>= 1, ++j)
5283 if (!(map & 1)) continue;
5285 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5286 object->contained_tss_states[object->num_contained_tss_states].state = j;
5287 ++object->num_contained_tss_states;
5290 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5291 DWORD map = object->changed.samplerState[i];
5293 for (j = 0; map; map >>= 1, ++j)
5295 if (!(map & 1)) continue;
5297 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5298 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5299 ++object->num_contained_sampler_states;
5303 *ppStateBlock = (IWineD3DStateBlock*) object;
5304 This->isRecordingState = FALSE;
5305 This->updateStateBlock = This->stateBlock;
5306 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5307 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5308 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5309 return WINED3D_OK;
5312 /*****
5313 * Scene related functions
5314 *****/
5315 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5316 /* At the moment we have no need for any functionality at the beginning
5317 of a scene */
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5319 TRACE("(%p)\n", This);
5321 if(This->inScene) {
5322 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5323 return WINED3DERR_INVALIDCALL;
5325 This->inScene = TRUE;
5326 return WINED3D_OK;
5329 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 TRACE("(%p)\n", This);
5333 if(!This->inScene) {
5334 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5335 return WINED3DERR_INVALIDCALL;
5338 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5339 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5340 glFlush();
5341 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5342 * fails
5345 This->inScene = FALSE;
5346 return WINED3D_OK;
5349 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5350 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5351 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 IWineD3DSwapChain *swapChain = NULL;
5354 int i;
5355 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5357 TRACE("(%p) Presenting the frame\n", This);
5359 for(i = 0 ; i < swapchains ; i ++) {
5361 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5362 TRACE("presentinng chain %d, %p\n", i, swapChain);
5363 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5364 IWineD3DSwapChain_Release(swapChain);
5367 return WINED3D_OK;
5370 /* Not called from the VTable (internal subroutine) */
5371 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5372 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5373 float Z, DWORD Stencil) {
5374 GLbitfield glMask = 0;
5375 unsigned int i;
5376 WINED3DRECT curRect;
5377 RECT vp_rect;
5378 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5379 UINT drawable_width, drawable_height;
5380 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5381 IWineD3DSwapChainImpl *swapchain = NULL;
5383 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5384 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5385 * for the cleared parts, and the untouched parts.
5387 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5388 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5389 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5390 * checking all this if the dest surface is in the drawable anyway.
5392 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5393 while(1) {
5394 if(vp->X != 0 || vp->Y != 0 ||
5395 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5396 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5397 break;
5399 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5400 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5401 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5402 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5403 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5404 break;
5406 if(Count > 0 && pRects && (
5407 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5408 pRects[0].x2 < target->currentDesc.Width ||
5409 pRects[0].y2 < target->currentDesc.Height)) {
5410 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5411 break;
5413 break;
5417 target->get_drawable_size(target, &drawable_width, &drawable_height);
5419 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5420 ENTER_GL();
5422 /* Only set the values up once, as they are not changing */
5423 if (Flags & WINED3DCLEAR_STENCIL) {
5424 glClearStencil(Stencil);
5425 checkGLcall("glClearStencil");
5426 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5427 glStencilMask(0xFFFFFFFF);
5430 if (Flags & WINED3DCLEAR_ZBUFFER) {
5431 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5432 glDepthMask(GL_TRUE);
5433 glClearDepth(Z);
5434 checkGLcall("glClearDepth");
5435 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5438 if (vp->X != 0 || vp->Y != 0 ||
5439 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5440 surface_load_ds_location(This->stencilBufferTarget, location);
5442 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5443 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5444 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5445 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5446 surface_load_ds_location(This->stencilBufferTarget, location);
5448 else if (Count > 0 && pRects && (
5449 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5450 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5451 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5452 surface_load_ds_location(This->stencilBufferTarget, location);
5456 if (Flags & WINED3DCLEAR_TARGET) {
5457 TRACE("Clearing screen with glClear to color %x\n", Color);
5458 glClearColor(D3DCOLOR_R(Color),
5459 D3DCOLOR_G(Color),
5460 D3DCOLOR_B(Color),
5461 D3DCOLOR_A(Color));
5462 checkGLcall("glClearColor");
5464 /* Clear ALL colors! */
5465 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5466 glMask = glMask | GL_COLOR_BUFFER_BIT;
5469 vp_rect.left = vp->X;
5470 vp_rect.top = vp->Y;
5471 vp_rect.right = vp->X + vp->Width;
5472 vp_rect.bottom = vp->Y + vp->Height;
5473 if (!(Count > 0 && pRects)) {
5474 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5475 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5477 if(This->render_offscreen) {
5478 glScissor(vp_rect.left, vp_rect.top,
5479 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5480 } else {
5481 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5482 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5484 checkGLcall("glScissor");
5485 glClear(glMask);
5486 checkGLcall("glClear");
5487 } else {
5488 /* Now process each rect in turn */
5489 for (i = 0; i < Count; i++) {
5490 /* Note gl uses lower left, width/height */
5491 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5492 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5493 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5495 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5496 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5497 curRect.x1, (target->currentDesc.Height - curRect.y2),
5498 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5500 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5501 * The rectangle is not cleared, no error is returned, but further rectanlges are
5502 * still cleared if they are valid
5504 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5505 TRACE("Rectangle with negative dimensions, ignoring\n");
5506 continue;
5509 if(This->render_offscreen) {
5510 glScissor(curRect.x1, curRect.y1,
5511 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5512 } else {
5513 glScissor(curRect.x1, drawable_height - curRect.y2,
5514 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5516 checkGLcall("glScissor");
5518 glClear(glMask);
5519 checkGLcall("glClear");
5523 /* Restore the old values (why..?) */
5524 if (Flags & WINED3DCLEAR_STENCIL) {
5525 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5527 if (Flags & WINED3DCLEAR_TARGET) {
5528 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5529 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5530 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5531 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5532 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5534 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5535 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5537 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5539 if (Flags & WINED3DCLEAR_ZBUFFER) {
5540 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5541 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5542 surface_modify_ds_location(This->stencilBufferTarget, location);
5545 LEAVE_GL();
5547 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5548 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5549 glFlush();
5551 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5554 return WINED3D_OK;
5557 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5558 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5560 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5562 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5563 Count, pRects, Flags, Color, Z, Stencil);
5565 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5566 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5567 /* TODO: What about depth stencil buffers without stencil bits? */
5568 return WINED3DERR_INVALIDCALL;
5571 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5574 /*****
5575 * Drawing functions
5576 *****/
5578 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5579 WINED3DPRIMITIVETYPE primitive_type)
5581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5585 This->updateStateBlock->changed.primitive_type = TRUE;
5586 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5589 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5590 WINED3DPRIMITIVETYPE *primitive_type)
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5596 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5598 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5601 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5605 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5607 if(!This->stateBlock->vertexDecl) {
5608 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5609 return WINED3DERR_INVALIDCALL;
5612 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5613 if(This->stateBlock->streamIsUP) {
5614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5615 This->stateBlock->streamIsUP = FALSE;
5618 if(This->stateBlock->loadBaseVertexIndex != 0) {
5619 This->stateBlock->loadBaseVertexIndex = 0;
5620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5622 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5623 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5624 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5625 return WINED3D_OK;
5628 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5629 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 UINT idxStride = 2;
5633 IWineD3DBuffer *pIB;
5634 GLuint vbo;
5636 pIB = This->stateBlock->pIndexData;
5637 if (!pIB) {
5638 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5639 * without an index buffer set. (The first time at least...)
5640 * D3D8 simply dies, but I doubt it can do much harm to return
5641 * D3DERR_INVALIDCALL there as well. */
5642 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5643 return WINED3DERR_INVALIDCALL;
5646 if(!This->stateBlock->vertexDecl) {
5647 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5648 return WINED3DERR_INVALIDCALL;
5651 if(This->stateBlock->streamIsUP) {
5652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5653 This->stateBlock->streamIsUP = FALSE;
5655 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5657 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5658 This, minIndex, NumVertices, startIndex, index_count);
5660 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5661 idxStride = 2;
5662 } else {
5663 idxStride = 4;
5666 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5667 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5671 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5672 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5674 return WINED3D_OK;
5677 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5678 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 IWineD3DBuffer *vb;
5683 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5684 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5686 if(!This->stateBlock->vertexDecl) {
5687 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5688 return WINED3DERR_INVALIDCALL;
5691 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5692 vb = This->stateBlock->streamSource[0];
5693 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5694 if (vb) IWineD3DBuffer_Release(vb);
5695 This->stateBlock->streamOffset[0] = 0;
5696 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5697 This->stateBlock->streamIsUP = TRUE;
5698 This->stateBlock->loadBaseVertexIndex = 0;
5700 /* TODO: Only mark dirty if drawing from a different UP address */
5701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5703 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5704 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5706 /* MSDN specifies stream zero settings must be set to NULL */
5707 This->stateBlock->streamStride[0] = 0;
5708 This->stateBlock->streamSource[0] = NULL;
5710 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5711 * the new stream sources or use UP drawing again
5713 return WINED3D_OK;
5716 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5717 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5718 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5720 int idxStride;
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5722 IWineD3DBuffer *vb;
5723 IWineD3DBuffer *ib;
5725 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5726 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5727 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5729 if(!This->stateBlock->vertexDecl) {
5730 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5731 return WINED3DERR_INVALIDCALL;
5734 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5735 idxStride = 2;
5736 } else {
5737 idxStride = 4;
5740 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5741 vb = This->stateBlock->streamSource[0];
5742 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5743 if (vb) IWineD3DBuffer_Release(vb);
5744 This->stateBlock->streamIsUP = TRUE;
5745 This->stateBlock->streamOffset[0] = 0;
5746 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5748 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5749 This->stateBlock->baseVertexIndex = 0;
5750 This->stateBlock->loadBaseVertexIndex = 0;
5751 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5755 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5756 idxStride, pIndexData, MinVertexIndex);
5758 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5759 This->stateBlock->streamSource[0] = NULL;
5760 This->stateBlock->streamStride[0] = 0;
5761 ib = This->stateBlock->pIndexData;
5762 if(ib) {
5763 IWineD3DBuffer_Release(ib);
5764 This->stateBlock->pIndexData = NULL;
5766 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5767 * SetStreamSource to specify a vertex buffer
5770 return WINED3D_OK;
5773 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5774 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5778 /* Mark the state dirty until we have nicer tracking
5779 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5780 * that value.
5782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5784 This->stateBlock->baseVertexIndex = 0;
5785 This->up_strided = DrawPrimStrideData;
5786 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5787 This->up_strided = NULL;
5788 return WINED3D_OK;
5791 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5792 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5793 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5796 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5798 /* Mark the state dirty until we have nicer tracking
5799 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5800 * that value.
5802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5804 This->stateBlock->streamIsUP = TRUE;
5805 This->stateBlock->baseVertexIndex = 0;
5806 This->up_strided = DrawPrimStrideData;
5807 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5808 This->up_strided = NULL;
5809 return WINED3D_OK;
5812 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5813 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5814 * not callable by the app directly no parameter validation checks are needed here.
5816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5817 WINED3DLOCKED_BOX src;
5818 WINED3DLOCKED_BOX dst;
5819 HRESULT hr;
5820 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5822 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5823 * dirtification to improve loading performance.
5825 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5826 if(FAILED(hr)) return hr;
5827 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5828 if(FAILED(hr)) {
5829 IWineD3DVolume_UnlockBox(pSourceVolume);
5830 return hr;
5833 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5835 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5836 if(FAILED(hr)) {
5837 IWineD3DVolume_UnlockBox(pSourceVolume);
5838 } else {
5839 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5841 return hr;
5844 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5845 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5847 HRESULT hr = WINED3D_OK;
5848 WINED3DRESOURCETYPE sourceType;
5849 WINED3DRESOURCETYPE destinationType;
5850 int i ,levels;
5852 /* TODO: think about moving the code into IWineD3DBaseTexture */
5854 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5856 /* verify that the source and destination textures aren't NULL */
5857 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5858 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5859 This, pSourceTexture, pDestinationTexture);
5860 hr = WINED3DERR_INVALIDCALL;
5863 if (pSourceTexture == pDestinationTexture) {
5864 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5865 This, pSourceTexture, pDestinationTexture);
5866 hr = WINED3DERR_INVALIDCALL;
5868 /* Verify that the source and destination textures are the same type */
5869 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5870 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5872 if (sourceType != destinationType) {
5873 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5874 This);
5875 hr = WINED3DERR_INVALIDCALL;
5878 /* check that both textures have the identical numbers of levels */
5879 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5880 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5881 hr = WINED3DERR_INVALIDCALL;
5884 if (WINED3D_OK == hr) {
5885 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5887 /* Make sure that the destination texture is loaded */
5888 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5890 /* Update every surface level of the texture */
5891 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5893 switch (sourceType) {
5894 case WINED3DRTYPE_TEXTURE:
5896 IWineD3DSurface *srcSurface;
5897 IWineD3DSurface *destSurface;
5899 for (i = 0 ; i < levels ; ++i) {
5900 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5901 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5902 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5903 IWineD3DSurface_Release(srcSurface);
5904 IWineD3DSurface_Release(destSurface);
5905 if (WINED3D_OK != hr) {
5906 WARN("(%p) : Call to update surface failed\n", This);
5907 return hr;
5911 break;
5912 case WINED3DRTYPE_CUBETEXTURE:
5914 IWineD3DSurface *srcSurface;
5915 IWineD3DSurface *destSurface;
5916 WINED3DCUBEMAP_FACES faceType;
5918 for (i = 0 ; i < levels ; ++i) {
5919 /* Update each cube face */
5920 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5921 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5922 if (WINED3D_OK != hr) {
5923 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5924 } else {
5925 TRACE("Got srcSurface %p\n", srcSurface);
5927 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5928 if (WINED3D_OK != hr) {
5929 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5930 } else {
5931 TRACE("Got desrSurface %p\n", destSurface);
5933 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5934 IWineD3DSurface_Release(srcSurface);
5935 IWineD3DSurface_Release(destSurface);
5936 if (WINED3D_OK != hr) {
5937 WARN("(%p) : Call to update surface failed\n", This);
5938 return hr;
5943 break;
5945 case WINED3DRTYPE_VOLUMETEXTURE:
5947 IWineD3DVolume *srcVolume = NULL;
5948 IWineD3DVolume *destVolume = NULL;
5950 for (i = 0 ; i < levels ; ++i) {
5951 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5952 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5953 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5954 IWineD3DVolume_Release(srcVolume);
5955 IWineD3DVolume_Release(destVolume);
5956 if (WINED3D_OK != hr) {
5957 WARN("(%p) : Call to update volume failed\n", This);
5958 return hr;
5962 break;
5964 default:
5965 FIXME("(%p) : Unsupported source and destination type\n", This);
5966 hr = WINED3DERR_INVALIDCALL;
5970 return hr;
5973 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5974 IWineD3DSwapChain *swapChain;
5975 HRESULT hr;
5976 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5977 if(hr == WINED3D_OK) {
5978 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5979 IWineD3DSwapChain_Release(swapChain);
5981 return hr;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 IWineD3DBaseTextureImpl *texture;
5987 DWORD i;
5989 TRACE("(%p) : %p\n", This, pNumPasses);
5991 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5992 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5993 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5994 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5996 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5997 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5998 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6001 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
6002 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6004 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6005 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6006 return E_FAIL;
6008 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6009 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6010 return E_FAIL;
6012 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6013 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6014 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6015 return E_FAIL;
6019 /* return a sensible default */
6020 *pNumPasses = 1;
6022 TRACE("returning D3D_OK\n");
6023 return WINED3D_OK;
6026 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6028 int i;
6030 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6031 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6032 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6033 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6035 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6040 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 int j;
6043 UINT NewSize;
6044 PALETTEENTRY **palettes;
6046 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6048 if (PaletteNumber >= MAX_PALETTES) {
6049 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6050 return WINED3DERR_INVALIDCALL;
6053 if (PaletteNumber >= This->NumberOfPalettes) {
6054 NewSize = This->NumberOfPalettes;
6055 do {
6056 NewSize *= 2;
6057 } while(PaletteNumber >= NewSize);
6058 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6059 if (!palettes) {
6060 ERR("Out of memory!\n");
6061 return E_OUTOFMEMORY;
6063 This->palettes = palettes;
6064 This->NumberOfPalettes = NewSize;
6067 if (!This->palettes[PaletteNumber]) {
6068 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6069 if (!This->palettes[PaletteNumber]) {
6070 ERR("Out of memory!\n");
6071 return E_OUTOFMEMORY;
6075 for (j = 0; j < 256; ++j) {
6076 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6077 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6078 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6079 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6081 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6082 TRACE("(%p) : returning\n", This);
6083 return WINED3D_OK;
6086 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6088 int j;
6089 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6090 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6091 /* What happens in such situation isn't documented; Native seems to silently abort
6092 on such conditions. Return Invalid Call. */
6093 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6094 return WINED3DERR_INVALIDCALL;
6096 for (j = 0; j < 256; ++j) {
6097 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6098 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6099 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6100 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6102 TRACE("(%p) : returning\n", This);
6103 return WINED3D_OK;
6106 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6108 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6109 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6110 (tested with reference rasterizer). Return Invalid Call. */
6111 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6112 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6113 return WINED3DERR_INVALIDCALL;
6115 /*TODO: stateblocks */
6116 if (This->currentPalette != PaletteNumber) {
6117 This->currentPalette = PaletteNumber;
6118 dirtify_p8_texture_samplers(This);
6120 TRACE("(%p) : returning\n", This);
6121 return WINED3D_OK;
6124 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 if (PaletteNumber == NULL) {
6127 WARN("(%p) : returning Invalid Call\n", This);
6128 return WINED3DERR_INVALIDCALL;
6130 /*TODO: stateblocks */
6131 *PaletteNumber = This->currentPalette;
6132 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6133 return WINED3D_OK;
6136 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6138 static BOOL warned;
6139 if (!warned)
6141 FIXME("(%p) : stub\n", This);
6142 warned = TRUE;
6145 This->softwareVertexProcessing = bSoftware;
6146 return WINED3D_OK;
6150 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6152 static BOOL warned;
6153 if (!warned)
6155 FIXME("(%p) : stub\n", This);
6156 warned = TRUE;
6158 return This->softwareVertexProcessing;
6162 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6164 IWineD3DSwapChain *swapChain;
6165 HRESULT hr;
6167 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6169 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6170 if(hr == WINED3D_OK){
6171 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6172 IWineD3DSwapChain_Release(swapChain);
6173 }else{
6174 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6176 return hr;
6180 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6182 static BOOL warned;
6183 if(nSegments != 0.0f) {
6184 if (!warned)
6186 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6187 warned = TRUE;
6190 return WINED3D_OK;
6193 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6195 static BOOL warned;
6196 if (!warned)
6198 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6199 warned = TRUE;
6201 return 0.0f;
6204 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6206 /** TODO: remove casts to IWineD3DSurfaceImpl
6207 * NOTE: move code to surface to accomplish this
6208 ****************************************/
6209 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6210 int srcWidth, srcHeight;
6211 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6212 WINED3DFORMAT destFormat, srcFormat;
6213 UINT destSize;
6214 int srcLeft, destLeft, destTop;
6215 WINED3DPOOL srcPool, destPool;
6216 int offset = 0;
6217 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6218 glDescriptor *glDescription = NULL;
6219 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6220 GLenum dummy;
6221 int sampler;
6222 int bpp;
6223 CONVERT_TYPES convert = NO_CONVERSION;
6225 WINED3DSURFACE_DESC winedesc;
6227 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6228 memset(&winedesc, 0, sizeof(winedesc));
6229 winedesc.Width = &srcSurfaceWidth;
6230 winedesc.Height = &srcSurfaceHeight;
6231 winedesc.Pool = &srcPool;
6232 winedesc.Format = &srcFormat;
6234 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6236 winedesc.Width = &destSurfaceWidth;
6237 winedesc.Height = &destSurfaceHeight;
6238 winedesc.Pool = &destPool;
6239 winedesc.Format = &destFormat;
6240 winedesc.Size = &destSize;
6242 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6244 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6245 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6246 return WINED3DERR_INVALIDCALL;
6249 /* This call loads the opengl surface directly, instead of copying the surface to the
6250 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6251 * copy in sysmem and use regular surface loading.
6253 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6254 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6255 if(convert != NO_CONVERSION) {
6256 return IWineD3DSurface_BltFast(pDestinationSurface,
6257 pDestPoint ? pDestPoint->x : 0,
6258 pDestPoint ? pDestPoint->y : 0,
6259 pSourceSurface, pSourceRect, 0);
6262 if (destFormat == WINED3DFMT_UNKNOWN) {
6263 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6264 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6266 /* Get the update surface description */
6267 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6270 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6272 ENTER_GL();
6273 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6274 checkGLcall("glActiveTextureARB");
6275 LEAVE_GL();
6277 /* Make sure the surface is loaded and up to date */
6278 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6279 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6281 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6283 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6284 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6286 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6287 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6288 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6289 srcLeft = pSourceRect ? pSourceRect->left : 0;
6290 destLeft = pDestPoint ? pDestPoint->x : 0;
6291 destTop = pDestPoint ? pDestPoint->y : 0;
6294 /* This function doesn't support compressed textures
6295 the pitch is just bytesPerPixel * width */
6296 if(srcWidth != srcSurfaceWidth || srcLeft ){
6297 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6298 offset += srcLeft * src_format_desc->byte_count;
6299 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6301 /* TODO DXT formats */
6303 if(pSourceRect != NULL && pSourceRect->top != 0){
6304 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6306 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6307 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6308 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6310 /* Sanity check */
6311 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6313 /* need to lock the surface to get the data */
6314 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6317 ENTER_GL();
6319 /* TODO: Cube and volume support */
6320 if(rowoffset != 0){
6321 /* not a whole row so we have to do it a line at a time */
6322 int j;
6324 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6325 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6327 for (j = destTop; j < (srcHeight + destTop); ++j)
6329 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6330 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6331 data += rowoffset;
6334 } else { /* Full width, so just write out the whole texture */
6335 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6337 if (WINED3DFMT_DXT1 == destFormat ||
6338 WINED3DFMT_DXT2 == destFormat ||
6339 WINED3DFMT_DXT3 == destFormat ||
6340 WINED3DFMT_DXT4 == destFormat ||
6341 WINED3DFMT_DXT5 == destFormat) {
6342 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6343 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6344 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6345 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6346 } if (destFormat != srcFormat) {
6347 FIXME("Updating mixed format compressed texture is not curretly support\n");
6348 } else {
6349 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6350 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6352 } else {
6353 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6357 } else {
6358 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6359 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6362 checkGLcall("glTexSubImage2D");
6364 LEAVE_GL();
6366 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6367 sampler = This->rev_tex_unit_map[0];
6368 if (sampler != -1) {
6369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6372 return WINED3D_OK;
6375 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6377 struct WineD3DRectPatch *patch;
6378 GLenum old_primitive_type;
6379 unsigned int i;
6380 struct list *e;
6381 BOOL found;
6382 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6384 if(!(Handle || pRectPatchInfo)) {
6385 /* TODO: Write a test for the return value, thus the FIXME */
6386 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6387 return WINED3DERR_INVALIDCALL;
6390 if(Handle) {
6391 i = PATCHMAP_HASHFUNC(Handle);
6392 found = FALSE;
6393 LIST_FOR_EACH(e, &This->patches[i]) {
6394 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6395 if(patch->Handle == Handle) {
6396 found = TRUE;
6397 break;
6401 if(!found) {
6402 TRACE("Patch does not exist. Creating a new one\n");
6403 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6404 patch->Handle = Handle;
6405 list_add_head(&This->patches[i], &patch->entry);
6406 } else {
6407 TRACE("Found existing patch %p\n", patch);
6409 } else {
6410 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6411 * attributes we have to tesselate, read back, and draw. This needs a patch
6412 * management structure instance. Create one.
6414 * A possible improvement is to check if a vertex shader is used, and if not directly
6415 * draw the patch.
6417 FIXME("Drawing an uncached patch. This is slow\n");
6418 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6421 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6422 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6423 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6424 HRESULT hr;
6425 TRACE("Tesselation density or patch info changed, retesselating\n");
6427 if(pRectPatchInfo) {
6428 patch->RectPatchInfo = *pRectPatchInfo;
6430 patch->numSegs[0] = pNumSegs[0];
6431 patch->numSegs[1] = pNumSegs[1];
6432 patch->numSegs[2] = pNumSegs[2];
6433 patch->numSegs[3] = pNumSegs[3];
6435 hr = tesselate_rectpatch(This, patch);
6436 if(FAILED(hr)) {
6437 WARN("Patch tesselation failed\n");
6439 /* Do not release the handle to store the params of the patch */
6440 if(!Handle) {
6441 HeapFree(GetProcessHeap(), 0, patch);
6443 return hr;
6447 This->currentPatch = patch;
6448 old_primitive_type = This->stateBlock->gl_primitive_type;
6449 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6450 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6451 This->stateBlock->gl_primitive_type = old_primitive_type;
6452 This->currentPatch = NULL;
6454 /* Destroy uncached patches */
6455 if(!Handle) {
6456 HeapFree(GetProcessHeap(), 0, patch->mem);
6457 HeapFree(GetProcessHeap(), 0, patch);
6459 return WINED3D_OK;
6462 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6464 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6465 FIXME("(%p) : Stub\n", This);
6466 return WINED3D_OK;
6469 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6471 int i;
6472 struct WineD3DRectPatch *patch;
6473 struct list *e;
6474 TRACE("(%p) Handle(%d)\n", This, Handle);
6476 i = PATCHMAP_HASHFUNC(Handle);
6477 LIST_FOR_EACH(e, &This->patches[i]) {
6478 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6479 if(patch->Handle == Handle) {
6480 TRACE("Deleting patch %p\n", patch);
6481 list_remove(&patch->entry);
6482 HeapFree(GetProcessHeap(), 0, patch->mem);
6483 HeapFree(GetProcessHeap(), 0, patch);
6484 return WINED3D_OK;
6488 /* TODO: Write a test for the return value */
6489 FIXME("Attempt to destroy nonexistent patch\n");
6490 return WINED3DERR_INVALIDCALL;
6493 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6494 HRESULT hr;
6495 IWineD3DSwapChain *swapchain;
6497 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6498 if (SUCCEEDED(hr)) {
6499 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6500 return swapchain;
6503 return NULL;
6506 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6507 const WINED3DRECT *rect, const float color[4])
6509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6510 IWineD3DSwapChain *swapchain;
6512 swapchain = get_swapchain(surface);
6513 if (swapchain) {
6514 GLenum buffer;
6516 TRACE("Surface %p is onscreen\n", surface);
6518 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6519 ENTER_GL();
6520 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6521 buffer = surface_get_gl_buffer(surface, swapchain);
6522 glDrawBuffer(buffer);
6523 checkGLcall("glDrawBuffer()");
6524 } else {
6525 TRACE("Surface %p is offscreen\n", surface);
6527 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6528 ENTER_GL();
6529 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6530 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6531 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6532 checkGLcall("glFramebufferRenderbufferEXT");
6535 if (rect) {
6536 glEnable(GL_SCISSOR_TEST);
6537 if(!swapchain) {
6538 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6539 } else {
6540 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6541 rect->x2 - rect->x1, rect->y2 - rect->y1);
6543 checkGLcall("glScissor");
6544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6545 } else {
6546 glDisable(GL_SCISSOR_TEST);
6548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6550 glDisable(GL_BLEND);
6551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6553 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6556 glClearColor(color[0], color[1], color[2], color[3]);
6557 glClear(GL_COLOR_BUFFER_BIT);
6558 checkGLcall("glClear");
6560 if (This->activeContext->current_fbo) {
6561 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6562 } else {
6563 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6564 checkGLcall("glBindFramebuffer()");
6567 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6568 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6569 glDrawBuffer(GL_BACK);
6570 checkGLcall("glDrawBuffer()");
6573 LEAVE_GL();
6576 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6577 unsigned int r, g, b, a;
6578 DWORD ret;
6580 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6581 destfmt == WINED3DFMT_R8G8B8)
6582 return color;
6584 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6586 a = (color & 0xff000000) >> 24;
6587 r = (color & 0x00ff0000) >> 16;
6588 g = (color & 0x0000ff00) >> 8;
6589 b = (color & 0x000000ff) >> 0;
6591 switch(destfmt)
6593 case WINED3DFMT_R5G6B5:
6594 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6595 r = (r * 32) / 256;
6596 g = (g * 64) / 256;
6597 b = (b * 32) / 256;
6598 ret = r << 11;
6599 ret |= g << 5;
6600 ret |= b;
6601 TRACE("Returning %08x\n", ret);
6602 return ret;
6604 case WINED3DFMT_X1R5G5B5:
6605 case WINED3DFMT_A1R5G5B5:
6606 a = (a * 2) / 256;
6607 r = (r * 32) / 256;
6608 g = (g * 32) / 256;
6609 b = (b * 32) / 256;
6610 ret = a << 15;
6611 ret |= r << 10;
6612 ret |= g << 5;
6613 ret |= b << 0;
6614 TRACE("Returning %08x\n", ret);
6615 return ret;
6617 case WINED3DFMT_A8_UNORM:
6618 TRACE("Returning %08x\n", a);
6619 return a;
6621 case WINED3DFMT_X4R4G4B4:
6622 case WINED3DFMT_A4R4G4B4:
6623 a = (a * 16) / 256;
6624 r = (r * 16) / 256;
6625 g = (g * 16) / 256;
6626 b = (b * 16) / 256;
6627 ret = a << 12;
6628 ret |= r << 8;
6629 ret |= g << 4;
6630 ret |= b << 0;
6631 TRACE("Returning %08x\n", ret);
6632 return ret;
6634 case WINED3DFMT_R3G3B2:
6635 r = (r * 8) / 256;
6636 g = (g * 8) / 256;
6637 b = (b * 4) / 256;
6638 ret = r << 5;
6639 ret |= g << 2;
6640 ret |= b << 0;
6641 TRACE("Returning %08x\n", ret);
6642 return ret;
6644 case WINED3DFMT_X8B8G8R8:
6645 case WINED3DFMT_R8G8B8A8_UNORM:
6646 ret = a << 24;
6647 ret |= b << 16;
6648 ret |= g << 8;
6649 ret |= r << 0;
6650 TRACE("Returning %08x\n", ret);
6651 return ret;
6653 case WINED3DFMT_A2R10G10B10:
6654 a = (a * 4) / 256;
6655 r = (r * 1024) / 256;
6656 g = (g * 1024) / 256;
6657 b = (b * 1024) / 256;
6658 ret = a << 30;
6659 ret |= r << 20;
6660 ret |= g << 10;
6661 ret |= b << 0;
6662 TRACE("Returning %08x\n", ret);
6663 return ret;
6665 case WINED3DFMT_R10G10B10A2_UNORM:
6666 a = (a * 4) / 256;
6667 r = (r * 1024) / 256;
6668 g = (g * 1024) / 256;
6669 b = (b * 1024) / 256;
6670 ret = a << 30;
6671 ret |= b << 20;
6672 ret |= g << 10;
6673 ret |= r << 0;
6674 TRACE("Returning %08x\n", ret);
6675 return ret;
6677 default:
6678 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6679 return 0;
6683 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6685 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6686 WINEDDBLTFX BltFx;
6687 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6689 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6690 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6691 return WINED3DERR_INVALIDCALL;
6694 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6695 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6696 color_fill_fbo(iface, pSurface, pRect, c);
6697 return WINED3D_OK;
6698 } else {
6699 /* Just forward this to the DirectDraw blitting engine */
6700 memset(&BltFx, 0, sizeof(BltFx));
6701 BltFx.dwSize = sizeof(BltFx);
6702 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6703 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6704 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6708 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6709 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6711 IWineD3DResource *resource;
6712 IWineD3DSurface *surface;
6713 HRESULT hr;
6715 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6716 if (FAILED(hr))
6718 ERR("Failed to get resource, hr %#x\n", hr);
6719 return;
6722 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6724 FIXME("Only supported on surface resources\n");
6725 IWineD3DResource_Release(resource);
6726 return;
6729 surface = (IWineD3DSurface *)resource;
6731 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6733 color_fill_fbo(iface, surface, NULL, color);
6735 else
6737 WINEDDBLTFX BltFx;
6738 WINED3DCOLOR c;
6740 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6742 c = ((DWORD)(color[2] * 255.0));
6743 c |= ((DWORD)(color[1] * 255.0)) << 8;
6744 c |= ((DWORD)(color[0] * 255.0)) << 16;
6745 c |= ((DWORD)(color[3] * 255.0)) << 24;
6747 /* Just forward this to the DirectDraw blitting engine */
6748 memset(&BltFx, 0, sizeof(BltFx));
6749 BltFx.dwSize = sizeof(BltFx);
6750 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6751 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6752 if (FAILED(hr))
6754 ERR("Blt failed, hr %#x\n", hr);
6758 IWineD3DResource_Release(resource);
6761 /* rendertarget and depth stencil functions */
6762 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6765 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6766 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6767 return WINED3DERR_INVALIDCALL;
6770 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6771 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6772 /* Note inc ref on returned surface */
6773 if(*ppRenderTarget != NULL)
6774 IWineD3DSurface_AddRef(*ppRenderTarget);
6775 return WINED3D_OK;
6778 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6780 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6781 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6782 IWineD3DSwapChainImpl *Swapchain;
6783 HRESULT hr;
6785 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6787 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6788 if(hr != WINED3D_OK) {
6789 ERR("Can't get the swapchain\n");
6790 return hr;
6793 /* Make sure to release the swapchain */
6794 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6796 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6797 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6798 return WINED3DERR_INVALIDCALL;
6800 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6801 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6802 return WINED3DERR_INVALIDCALL;
6805 if(Swapchain->frontBuffer != Front) {
6806 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6808 if(Swapchain->frontBuffer)
6810 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6811 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6813 Swapchain->frontBuffer = Front;
6815 if(Swapchain->frontBuffer) {
6816 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6817 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6821 if(Back && !Swapchain->backBuffer) {
6822 /* We need memory for the back buffer array - only one back buffer this way */
6823 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6824 if(!Swapchain->backBuffer) {
6825 ERR("Out of memory\n");
6826 return E_OUTOFMEMORY;
6830 if(Swapchain->backBuffer[0] != Back) {
6831 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6833 /* What to do about the context here in the case of multithreading? Not sure.
6834 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6836 ENTER_GL();
6837 if(!Swapchain->backBuffer[0]) {
6838 /* GL was told to draw to the front buffer at creation,
6839 * undo that
6841 glDrawBuffer(GL_BACK);
6842 checkGLcall("glDrawBuffer(GL_BACK)");
6843 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6844 Swapchain->presentParms.BackBufferCount = 1;
6845 } else if (!Back) {
6846 /* That makes problems - disable for now */
6847 /* glDrawBuffer(GL_FRONT); */
6848 checkGLcall("glDrawBuffer(GL_FRONT)");
6849 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6850 Swapchain->presentParms.BackBufferCount = 0;
6852 LEAVE_GL();
6854 if(Swapchain->backBuffer[0])
6856 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6857 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6859 Swapchain->backBuffer[0] = Back;
6861 if(Swapchain->backBuffer[0]) {
6862 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6863 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6864 } else {
6865 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6866 Swapchain->backBuffer = NULL;
6871 return WINED3D_OK;
6874 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6876 *ppZStencilSurface = This->stencilBufferTarget;
6877 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6879 if(*ppZStencilSurface != NULL) {
6880 /* Note inc ref on returned surface */
6881 IWineD3DSurface_AddRef(*ppZStencilSurface);
6882 return WINED3D_OK;
6883 } else {
6884 return WINED3DERR_NOTFOUND;
6888 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6889 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6892 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6893 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6894 GLenum gl_filter;
6895 POINT offset = {0, 0};
6897 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6898 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6899 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6900 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6902 switch (filter) {
6903 case WINED3DTEXF_LINEAR:
6904 gl_filter = GL_LINEAR;
6905 break;
6907 default:
6908 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6909 case WINED3DTEXF_NONE:
6910 case WINED3DTEXF_POINT:
6911 gl_filter = GL_NEAREST;
6912 break;
6915 /* Attach src surface to src fbo */
6916 src_swapchain = get_swapchain(src_surface);
6917 if (src_swapchain) {
6918 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6920 TRACE("Source surface %p is onscreen\n", src_surface);
6921 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6922 /* Make sure the drawable is up to date. In the offscreen case
6923 * attach_surface_fbo() implicitly takes care of this. */
6924 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6926 if(buffer == GL_FRONT) {
6927 RECT windowsize;
6928 UINT h;
6929 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6930 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6931 h = windowsize.bottom - windowsize.top;
6932 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6933 src_rect->y1 = offset.y + h - src_rect->y1;
6934 src_rect->y2 = offset.y + h - src_rect->y2;
6935 } else {
6936 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6937 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6940 ENTER_GL();
6941 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6942 glReadBuffer(buffer);
6943 checkGLcall("glReadBuffer()");
6944 } else {
6945 TRACE("Source surface %p is offscreen\n", src_surface);
6946 ENTER_GL();
6947 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6948 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6949 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6950 checkGLcall("glReadBuffer()");
6951 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6952 checkGLcall("glFramebufferRenderbufferEXT");
6954 LEAVE_GL();
6956 /* Attach dst surface to dst fbo */
6957 dst_swapchain = get_swapchain(dst_surface);
6958 if (dst_swapchain) {
6959 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6961 TRACE("Destination surface %p is onscreen\n", dst_surface);
6962 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6963 /* Make sure the drawable is up to date. In the offscreen case
6964 * attach_surface_fbo() implicitly takes care of this. */
6965 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6967 if(buffer == GL_FRONT) {
6968 RECT windowsize;
6969 UINT h;
6970 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6971 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6972 h = windowsize.bottom - windowsize.top;
6973 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6974 dst_rect->y1 = offset.y + h - dst_rect->y1;
6975 dst_rect->y2 = offset.y + h - dst_rect->y2;
6976 } else {
6977 /* Screen coords = window coords, surface height = window height */
6978 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6979 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6982 ENTER_GL();
6983 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6984 glDrawBuffer(buffer);
6985 checkGLcall("glDrawBuffer()");
6986 } else {
6987 TRACE("Destination surface %p is offscreen\n", dst_surface);
6989 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6990 if(!src_swapchain) {
6991 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6994 ENTER_GL();
6995 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6996 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6997 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6998 checkGLcall("glDrawBuffer()");
6999 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7000 checkGLcall("glFramebufferRenderbufferEXT");
7002 glDisable(GL_SCISSOR_TEST);
7003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7005 if (flip) {
7006 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7007 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7008 checkGLcall("glBlitFramebuffer()");
7009 } else {
7010 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7011 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7012 checkGLcall("glBlitFramebuffer()");
7015 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7017 if (This->activeContext->current_fbo) {
7018 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7019 } else {
7020 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7021 checkGLcall("glBindFramebuffer()");
7024 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7025 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7026 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7027 glDrawBuffer(GL_BACK);
7028 checkGLcall("glDrawBuffer()");
7030 LEAVE_GL();
7033 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7035 WINED3DVIEWPORT viewport;
7037 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7039 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7040 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7041 This, RenderTargetIndex, GL_LIMITS(buffers));
7042 return WINED3DERR_INVALIDCALL;
7045 /* MSDN says that null disables the render target
7046 but a device must always be associated with a render target
7047 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7049 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7050 FIXME("Trying to set render target 0 to NULL\n");
7051 return WINED3DERR_INVALIDCALL;
7053 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7054 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);
7055 return WINED3DERR_INVALIDCALL;
7058 /* If we are trying to set what we already have, don't bother */
7059 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7060 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7061 return WINED3D_OK;
7063 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7064 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7065 This->render_targets[RenderTargetIndex] = pRenderTarget;
7067 /* Render target 0 is special */
7068 if(RenderTargetIndex == 0) {
7069 /* Finally, reset the viewport as the MSDN states. */
7070 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7071 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7072 viewport.X = 0;
7073 viewport.Y = 0;
7074 viewport.MaxZ = 1.0f;
7075 viewport.MinZ = 0.0f;
7076 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7077 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7078 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7082 return WINED3D_OK;
7085 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7087 HRESULT hr = WINED3D_OK;
7088 IWineD3DSurface *tmp;
7090 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7092 if (pNewZStencil == This->stencilBufferTarget) {
7093 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7094 } else {
7095 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7096 * depending on the renter target implementation being used.
7097 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7098 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7099 * stencil buffer and incur an extra memory overhead
7100 ******************************************************/
7102 if (This->stencilBufferTarget) {
7103 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7104 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7105 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7106 } else {
7107 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7108 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7109 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7113 tmp = This->stencilBufferTarget;
7114 This->stencilBufferTarget = pNewZStencil;
7115 /* should we be calling the parent or the wined3d surface? */
7116 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7117 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7118 hr = WINED3D_OK;
7120 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7121 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7128 return hr;
7131 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7132 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7134 /* TODO: the use of Impl is deprecated. */
7135 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7136 WINED3DLOCKED_RECT lockedRect;
7138 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7140 /* some basic validation checks */
7141 if(This->cursorTexture) {
7142 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7143 ENTER_GL();
7144 glDeleteTextures(1, &This->cursorTexture);
7145 LEAVE_GL();
7146 This->cursorTexture = 0;
7149 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7150 This->haveHardwareCursor = TRUE;
7151 else
7152 This->haveHardwareCursor = FALSE;
7154 if(pCursorBitmap) {
7155 WINED3DLOCKED_RECT rect;
7157 /* MSDN: Cursor must be A8R8G8B8 */
7158 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7160 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7161 return WINED3DERR_INVALIDCALL;
7164 /* MSDN: Cursor must be smaller than the display mode */
7165 if(pSur->currentDesc.Width > This->ddraw_width ||
7166 pSur->currentDesc.Height > This->ddraw_height) {
7167 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);
7168 return WINED3DERR_INVALIDCALL;
7171 if (!This->haveHardwareCursor) {
7172 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7174 /* Do not store the surface's pointer because the application may
7175 * release it after setting the cursor image. Windows doesn't
7176 * addref the set surface, so we can't do this either without
7177 * creating circular refcount dependencies. Copy out the gl texture
7178 * instead.
7180 This->cursorWidth = pSur->currentDesc.Width;
7181 This->cursorHeight = pSur->currentDesc.Height;
7182 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7184 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7185 char *mem, *bits = rect.pBits;
7186 GLint intfmt = glDesc->glInternal;
7187 GLint format = glDesc->glFormat;
7188 GLint type = glDesc->glType;
7189 INT height = This->cursorHeight;
7190 INT width = This->cursorWidth;
7191 INT bpp = glDesc->byte_count;
7192 INT i, sampler;
7194 /* Reformat the texture memory (pitch and width can be
7195 * different) */
7196 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7197 for(i = 0; i < height; i++)
7198 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7199 IWineD3DSurface_UnlockRect(pCursorBitmap);
7200 ENTER_GL();
7202 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7203 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7204 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7207 /* Make sure that a proper texture unit is selected */
7208 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7209 checkGLcall("glActiveTextureARB");
7210 sampler = This->rev_tex_unit_map[0];
7211 if (sampler != -1) {
7212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7214 /* Create a new cursor texture */
7215 glGenTextures(1, &This->cursorTexture);
7216 checkGLcall("glGenTextures");
7217 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7218 checkGLcall("glBindTexture");
7219 /* Copy the bitmap memory into the cursor texture */
7220 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7221 HeapFree(GetProcessHeap(), 0, mem);
7222 checkGLcall("glTexImage2D");
7224 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7225 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7226 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7229 LEAVE_GL();
7231 else
7233 FIXME("A cursor texture was not returned.\n");
7234 This->cursorTexture = 0;
7237 else
7239 /* Draw a hardware cursor */
7240 ICONINFO cursorInfo;
7241 HCURSOR cursor;
7242 /* Create and clear maskBits because it is not needed for
7243 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7244 * chunks. */
7245 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7246 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7247 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7248 WINED3DLOCK_NO_DIRTY_UPDATE |
7249 WINED3DLOCK_READONLY
7251 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7252 pSur->currentDesc.Height);
7254 cursorInfo.fIcon = FALSE;
7255 cursorInfo.xHotspot = XHotSpot;
7256 cursorInfo.yHotspot = YHotSpot;
7257 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7258 pSur->currentDesc.Height, 1,
7259 1, &maskBits);
7260 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7261 pSur->currentDesc.Height, 1,
7262 32, lockedRect.pBits);
7263 IWineD3DSurface_UnlockRect(pCursorBitmap);
7264 /* Create our cursor and clean up. */
7265 cursor = CreateIconIndirect(&cursorInfo);
7266 SetCursor(cursor);
7267 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7268 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7269 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7270 This->hardwareCursor = cursor;
7271 HeapFree(GetProcessHeap(), 0, maskBits);
7275 This->xHotSpot = XHotSpot;
7276 This->yHotSpot = YHotSpot;
7277 return WINED3D_OK;
7280 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7282 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7284 This->xScreenSpace = XScreenSpace;
7285 This->yScreenSpace = YScreenSpace;
7287 return;
7291 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7293 BOOL oldVisible = This->bCursorVisible;
7294 POINT pt;
7296 TRACE("(%p) : visible(%d)\n", This, bShow);
7299 * When ShowCursor is first called it should make the cursor appear at the OS's last
7300 * known cursor position. Because of this, some applications just repetitively call
7301 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7303 GetCursorPos(&pt);
7304 This->xScreenSpace = pt.x;
7305 This->yScreenSpace = pt.y;
7307 if (This->haveHardwareCursor) {
7308 This->bCursorVisible = bShow;
7309 if (bShow)
7310 SetCursor(This->hardwareCursor);
7311 else
7312 SetCursor(NULL);
7314 else
7316 if (This->cursorTexture)
7317 This->bCursorVisible = bShow;
7320 return oldVisible;
7323 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7325 IWineD3DResourceImpl *resource;
7326 TRACE("(%p) : state (%u)\n", This, This->state);
7328 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7329 switch (This->state) {
7330 case WINED3D_OK:
7331 return WINED3D_OK;
7332 case WINED3DERR_DEVICELOST:
7334 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7335 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7336 return WINED3DERR_DEVICENOTRESET;
7338 return WINED3DERR_DEVICELOST;
7340 case WINED3DERR_DRIVERINTERNALERROR:
7341 return WINED3DERR_DRIVERINTERNALERROR;
7344 /* Unknown state */
7345 return WINED3DERR_DRIVERINTERNALERROR;
7349 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7351 /** FIXME: Resource tracking needs to be done,
7352 * The closes we can do to this is set the priorities of all managed textures low
7353 * and then reset them.
7354 ***********************************************************/
7355 FIXME("(%p) : stub\n", This);
7356 return WINED3D_OK;
7359 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7361 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7363 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7364 if(surface->Flags & SFLAG_DIBSECTION) {
7365 /* Release the DC */
7366 SelectObject(surface->hDC, surface->dib.holdbitmap);
7367 DeleteDC(surface->hDC);
7368 /* Release the DIB section */
7369 DeleteObject(surface->dib.DIBsection);
7370 surface->dib.bitmap_data = NULL;
7371 surface->resource.allocatedMemory = NULL;
7372 surface->Flags &= ~SFLAG_DIBSECTION;
7374 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7375 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7376 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7377 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7378 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7379 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7380 } else {
7381 surface->pow2Width = surface->pow2Height = 1;
7382 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7383 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7385 surface->glRect.left = 0;
7386 surface->glRect.top = 0;
7387 surface->glRect.right = surface->pow2Width;
7388 surface->glRect.bottom = surface->pow2Height;
7390 if(surface->glDescription.textureName) {
7391 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7392 ENTER_GL();
7393 glDeleteTextures(1, &surface->glDescription.textureName);
7394 LEAVE_GL();
7395 surface->glDescription.textureName = 0;
7396 surface->Flags &= ~SFLAG_CLIENT;
7398 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7399 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7400 surface->Flags |= SFLAG_NONPOW2;
7401 } else {
7402 surface->Flags &= ~SFLAG_NONPOW2;
7404 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7405 surface->resource.allocatedMemory = NULL;
7406 surface->resource.heapMemory = NULL;
7407 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7408 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7409 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7410 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7411 } else {
7412 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7416 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7417 TRACE("Unloading resource %p\n", resource);
7418 IWineD3DResource_UnLoad(resource);
7419 IWineD3DResource_Release(resource);
7420 return S_OK;
7423 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7425 UINT i, count;
7426 WINED3DDISPLAYMODE m;
7427 HRESULT hr;
7429 /* All Windowed modes are supported, as is leaving the current mode */
7430 if(pp->Windowed) return TRUE;
7431 if(!pp->BackBufferWidth) return TRUE;
7432 if(!pp->BackBufferHeight) return TRUE;
7434 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7435 for(i = 0; i < count; i++) {
7436 memset(&m, 0, sizeof(m));
7437 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7438 if(FAILED(hr)) {
7439 ERR("EnumAdapterModes failed\n");
7441 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7442 /* Mode found, it is supported */
7443 return TRUE;
7446 /* Mode not found -> not supported */
7447 return FALSE;
7450 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7452 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7453 UINT i;
7454 IWineD3DBaseShaderImpl *shader;
7456 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7457 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7458 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7461 ENTER_GL();
7462 if(This->depth_blt_texture) {
7463 glDeleteTextures(1, &This->depth_blt_texture);
7464 This->depth_blt_texture = 0;
7466 if (This->depth_blt_rb) {
7467 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7468 This->depth_blt_rb = 0;
7469 This->depth_blt_rb_w = 0;
7470 This->depth_blt_rb_h = 0;
7472 LEAVE_GL();
7474 This->blitter->free_private(iface);
7475 This->frag_pipe->free_private(iface);
7476 This->shader_backend->shader_free_private(iface);
7478 ENTER_GL();
7479 for (i = 0; i < GL_LIMITS(textures); i++) {
7480 /* Textures are recreated below */
7481 glDeleteTextures(1, &This->dummyTextureName[i]);
7482 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7483 This->dummyTextureName[i] = 0;
7485 LEAVE_GL();
7487 while(This->numContexts) {
7488 DestroyContext(This, This->contexts[0]);
7490 This->activeContext = NULL;
7491 HeapFree(GetProcessHeap(), 0, swapchain->context);
7492 swapchain->context = NULL;
7493 swapchain->num_contexts = 0;
7496 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7498 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7499 HRESULT hr;
7500 IWineD3DSurfaceImpl *target;
7502 /* Recreate the primary swapchain's context */
7503 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7504 if(swapchain->backBuffer) {
7505 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7506 } else {
7507 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7509 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7510 &swapchain->presentParms);
7511 swapchain->num_contexts = 1;
7512 This->activeContext = swapchain->context[0];
7514 create_dummy_textures(This);
7516 hr = This->shader_backend->shader_alloc_private(iface);
7517 if(FAILED(hr)) {
7518 ERR("Failed to recreate shader private data\n");
7519 goto err_out;
7521 hr = This->frag_pipe->alloc_private(iface);
7522 if(FAILED(hr)) {
7523 TRACE("Fragment pipeline private data couldn't be allocated\n");
7524 goto err_out;
7526 hr = This->blitter->alloc_private(iface);
7527 if(FAILED(hr)) {
7528 TRACE("Blitter private data couldn't be allocated\n");
7529 goto err_out;
7532 return WINED3D_OK;
7534 err_out:
7535 This->blitter->free_private(iface);
7536 This->frag_pipe->free_private(iface);
7537 This->shader_backend->shader_free_private(iface);
7538 return hr;
7541 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7543 IWineD3DSwapChainImpl *swapchain;
7544 HRESULT hr;
7545 BOOL DisplayModeChanged = FALSE;
7546 WINED3DDISPLAYMODE mode;
7547 TRACE("(%p)\n", This);
7549 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7550 if(FAILED(hr)) {
7551 ERR("Failed to get the first implicit swapchain\n");
7552 return hr;
7555 if(!is_display_mode_supported(This, pPresentationParameters)) {
7556 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7557 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7558 pPresentationParameters->BackBufferHeight);
7559 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7560 return WINED3DERR_INVALIDCALL;
7563 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7564 * on an existing gl context, so there's no real need for recreation.
7566 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7568 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7570 TRACE("New params:\n");
7571 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7572 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7573 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7574 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7575 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7576 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7577 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7578 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7579 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7580 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7581 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7582 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7583 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7585 /* No special treatment of these parameters. Just store them */
7586 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7587 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7588 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7589 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7591 /* What to do about these? */
7592 if(pPresentationParameters->BackBufferCount != 0 &&
7593 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7594 ERR("Cannot change the back buffer count yet\n");
7596 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7597 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7598 ERR("Cannot change the back buffer format yet\n");
7600 if(pPresentationParameters->hDeviceWindow != NULL &&
7601 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7602 ERR("Cannot change the device window yet\n");
7604 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7605 HRESULT hrc;
7607 TRACE("Creating the depth stencil buffer\n");
7609 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7610 This->parent,
7611 pPresentationParameters->BackBufferWidth,
7612 pPresentationParameters->BackBufferHeight,
7613 pPresentationParameters->AutoDepthStencilFormat,
7614 pPresentationParameters->MultiSampleType,
7615 pPresentationParameters->MultiSampleQuality,
7616 FALSE,
7617 &This->auto_depth_stencil_buffer);
7619 if (FAILED(hrc)) {
7620 ERR("Failed to create the depth stencil buffer\n");
7621 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7622 return WINED3DERR_INVALIDCALL;
7626 /* Reset the depth stencil */
7627 if (pPresentationParameters->EnableAutoDepthStencil)
7628 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7629 else
7630 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7632 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7634 if(pPresentationParameters->Windowed) {
7635 mode.Width = swapchain->orig_width;
7636 mode.Height = swapchain->orig_height;
7637 mode.RefreshRate = 0;
7638 mode.Format = swapchain->presentParms.BackBufferFormat;
7639 } else {
7640 mode.Width = pPresentationParameters->BackBufferWidth;
7641 mode.Height = pPresentationParameters->BackBufferHeight;
7642 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7643 mode.Format = swapchain->presentParms.BackBufferFormat;
7646 /* Should Width == 800 && Height == 0 set 800x600? */
7647 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7648 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7649 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7651 UINT i;
7653 if(!pPresentationParameters->Windowed) {
7654 DisplayModeChanged = TRUE;
7656 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7657 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7659 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7660 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7661 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7663 if(This->auto_depth_stencil_buffer) {
7664 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7668 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7669 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7670 DisplayModeChanged) {
7672 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7674 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7675 if(swapchain->presentParms.Windowed) {
7676 /* switch from windowed to fs */
7677 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7678 pPresentationParameters->BackBufferWidth,
7679 pPresentationParameters->BackBufferHeight);
7680 } else {
7681 /* Fullscreen -> fullscreen mode change */
7682 MoveWindow(swapchain->win_handle, 0, 0,
7683 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7684 TRUE);
7686 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7687 /* Fullscreen -> windowed switch */
7688 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7690 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7691 } else if(!pPresentationParameters->Windowed) {
7692 DWORD style = This->style, exStyle = This->exStyle;
7693 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7694 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7695 * Reset to clear up their mess. Guild Wars also loses the device during that.
7697 This->style = 0;
7698 This->exStyle = 0;
7699 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7700 pPresentationParameters->BackBufferWidth,
7701 pPresentationParameters->BackBufferHeight);
7702 This->style = style;
7703 This->exStyle = exStyle;
7706 TRACE("Resetting stateblock\n");
7707 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7708 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7710 /* Note: No parent needed for initial internal stateblock */
7711 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7712 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7713 else TRACE("Created stateblock %p\n", This->stateBlock);
7714 This->updateStateBlock = This->stateBlock;
7715 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7717 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7718 if(FAILED(hr)) {
7719 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7722 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7723 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7725 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7726 * first use
7728 return hr;
7731 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7733 /** FIXME: always true at the moment **/
7734 if(!bEnableDialogs) {
7735 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7737 return WINED3D_OK;
7741 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7743 TRACE("(%p) : pParameters %p\n", This, pParameters);
7745 *pParameters = This->createParms;
7746 return WINED3D_OK;
7749 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7750 IWineD3DSwapChain *swapchain;
7752 TRACE("Relaying to swapchain\n");
7754 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7755 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7756 IWineD3DSwapChain_Release(swapchain);
7758 return;
7761 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7762 IWineD3DSwapChain *swapchain;
7764 TRACE("Relaying to swapchain\n");
7766 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7767 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7768 IWineD3DSwapChain_Release(swapchain);
7770 return;
7774 /** ********************************************************
7775 * Notification functions
7776 ** ********************************************************/
7777 /** This function must be called in the release of a resource when ref == 0,
7778 * the contents of resource must still be correct,
7779 * any handles to other resource held by the caller must be closed
7780 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7781 *****************************************************/
7782 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7785 TRACE("(%p) : Adding Resource %p\n", This, resource);
7786 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7789 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7792 TRACE("(%p) : Removing resource %p\n", This, resource);
7794 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7798 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7800 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7801 int counter;
7803 TRACE("(%p) : resource %p\n", This, resource);
7805 context_resource_released(iface, resource, type);
7807 switch (type) {
7808 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7809 case WINED3DRTYPE_SURFACE: {
7810 unsigned int i;
7812 /* Cleanup any FBO attachments if d3d is enabled */
7813 if(This->d3d_initialized) {
7814 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7815 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7817 TRACE("Last active render target destroyed\n");
7818 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7819 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7820 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7821 * and the lastActiveRenderTarget member shouldn't matter
7823 if(swapchain) {
7824 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7825 TRACE("Activating primary back buffer\n");
7826 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7827 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7828 /* Single buffering environment */
7829 TRACE("Activating primary front buffer\n");
7830 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7831 } else {
7832 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7833 /* Implicit render target destroyed, that means the device is being destroyed
7834 * whatever we set here, it shouldn't matter
7836 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7838 } else {
7839 /* May happen during ddraw uninitialization */
7840 TRACE("Render target set, but swapchain does not exist!\n");
7841 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7845 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7846 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7847 This->render_targets[i] = NULL;
7850 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7851 This->stencilBufferTarget = NULL;
7855 break;
7857 case WINED3DRTYPE_TEXTURE:
7858 case WINED3DRTYPE_CUBETEXTURE:
7859 case WINED3DRTYPE_VOLUMETEXTURE:
7860 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7861 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7862 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7863 This->stateBlock->textures[counter] = NULL;
7865 if (This->updateStateBlock != This->stateBlock ){
7866 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7867 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7868 This->updateStateBlock->textures[counter] = NULL;
7872 break;
7873 case WINED3DRTYPE_VOLUME:
7874 /* TODO: nothing really? */
7875 break;
7876 case WINED3DRTYPE_BUFFER:
7878 int streamNumber;
7879 TRACE("Cleaning up stream pointers\n");
7881 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7882 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7883 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7885 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7886 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7887 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7888 This->updateStateBlock->streamSource[streamNumber] = 0;
7889 /* Set changed flag? */
7892 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) */
7893 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7894 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7895 This->stateBlock->streamSource[streamNumber] = 0;
7900 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7901 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7902 This->updateStateBlock->pIndexData = NULL;
7905 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7906 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7907 This->stateBlock->pIndexData = NULL;
7911 break;
7913 default:
7914 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7915 break;
7919 /* Remove the resource from the resourceStore */
7920 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7922 TRACE("Resource released\n");
7926 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7928 IWineD3DResourceImpl *resource, *cursor;
7929 HRESULT ret;
7930 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7932 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7933 TRACE("enumerating resource %p\n", resource);
7934 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7935 ret = pCallback((IWineD3DResource *) resource, pData);
7936 if(ret == S_FALSE) {
7937 TRACE("Canceling enumeration\n");
7938 break;
7941 return WINED3D_OK;
7944 /**********************************************************
7945 * IWineD3DDevice VTbl follows
7946 **********************************************************/
7948 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7950 /*** IUnknown methods ***/
7951 IWineD3DDeviceImpl_QueryInterface,
7952 IWineD3DDeviceImpl_AddRef,
7953 IWineD3DDeviceImpl_Release,
7954 /*** IWineD3DDevice methods ***/
7955 IWineD3DDeviceImpl_GetParent,
7956 /*** Creation methods**/
7957 IWineD3DDeviceImpl_CreateBuffer,
7958 IWineD3DDeviceImpl_CreateVertexBuffer,
7959 IWineD3DDeviceImpl_CreateIndexBuffer,
7960 IWineD3DDeviceImpl_CreateStateBlock,
7961 IWineD3DDeviceImpl_CreateSurface,
7962 IWineD3DDeviceImpl_CreateRendertargetView,
7963 IWineD3DDeviceImpl_CreateTexture,
7964 IWineD3DDeviceImpl_CreateVolumeTexture,
7965 IWineD3DDeviceImpl_CreateVolume,
7966 IWineD3DDeviceImpl_CreateCubeTexture,
7967 IWineD3DDeviceImpl_CreateQuery,
7968 IWineD3DDeviceImpl_CreateSwapChain,
7969 IWineD3DDeviceImpl_CreateVertexDeclaration,
7970 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7971 IWineD3DDeviceImpl_CreateVertexShader,
7972 IWineD3DDeviceImpl_CreatePixelShader,
7973 IWineD3DDeviceImpl_CreatePalette,
7974 /*** Odd functions **/
7975 IWineD3DDeviceImpl_Init3D,
7976 IWineD3DDeviceImpl_InitGDI,
7977 IWineD3DDeviceImpl_Uninit3D,
7978 IWineD3DDeviceImpl_UninitGDI,
7979 IWineD3DDeviceImpl_SetMultithreaded,
7980 IWineD3DDeviceImpl_EvictManagedResources,
7981 IWineD3DDeviceImpl_GetAvailableTextureMem,
7982 IWineD3DDeviceImpl_GetBackBuffer,
7983 IWineD3DDeviceImpl_GetCreationParameters,
7984 IWineD3DDeviceImpl_GetDeviceCaps,
7985 IWineD3DDeviceImpl_GetDirect3D,
7986 IWineD3DDeviceImpl_GetDisplayMode,
7987 IWineD3DDeviceImpl_SetDisplayMode,
7988 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7989 IWineD3DDeviceImpl_GetRasterStatus,
7990 IWineD3DDeviceImpl_GetSwapChain,
7991 IWineD3DDeviceImpl_Reset,
7992 IWineD3DDeviceImpl_SetDialogBoxMode,
7993 IWineD3DDeviceImpl_SetCursorProperties,
7994 IWineD3DDeviceImpl_SetCursorPosition,
7995 IWineD3DDeviceImpl_ShowCursor,
7996 IWineD3DDeviceImpl_TestCooperativeLevel,
7997 /*** Getters and setters **/
7998 IWineD3DDeviceImpl_SetClipPlane,
7999 IWineD3DDeviceImpl_GetClipPlane,
8000 IWineD3DDeviceImpl_SetClipStatus,
8001 IWineD3DDeviceImpl_GetClipStatus,
8002 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8003 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8004 IWineD3DDeviceImpl_SetDepthStencilSurface,
8005 IWineD3DDeviceImpl_GetDepthStencilSurface,
8006 IWineD3DDeviceImpl_SetGammaRamp,
8007 IWineD3DDeviceImpl_GetGammaRamp,
8008 IWineD3DDeviceImpl_SetIndices,
8009 IWineD3DDeviceImpl_GetIndices,
8010 IWineD3DDeviceImpl_SetBaseVertexIndex,
8011 IWineD3DDeviceImpl_GetBaseVertexIndex,
8012 IWineD3DDeviceImpl_SetLight,
8013 IWineD3DDeviceImpl_GetLight,
8014 IWineD3DDeviceImpl_SetLightEnable,
8015 IWineD3DDeviceImpl_GetLightEnable,
8016 IWineD3DDeviceImpl_SetMaterial,
8017 IWineD3DDeviceImpl_GetMaterial,
8018 IWineD3DDeviceImpl_SetNPatchMode,
8019 IWineD3DDeviceImpl_GetNPatchMode,
8020 IWineD3DDeviceImpl_SetPaletteEntries,
8021 IWineD3DDeviceImpl_GetPaletteEntries,
8022 IWineD3DDeviceImpl_SetPixelShader,
8023 IWineD3DDeviceImpl_GetPixelShader,
8024 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8025 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8026 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8027 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8028 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8029 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8030 IWineD3DDeviceImpl_SetRenderState,
8031 IWineD3DDeviceImpl_GetRenderState,
8032 IWineD3DDeviceImpl_SetRenderTarget,
8033 IWineD3DDeviceImpl_GetRenderTarget,
8034 IWineD3DDeviceImpl_SetFrontBackBuffers,
8035 IWineD3DDeviceImpl_SetSamplerState,
8036 IWineD3DDeviceImpl_GetSamplerState,
8037 IWineD3DDeviceImpl_SetScissorRect,
8038 IWineD3DDeviceImpl_GetScissorRect,
8039 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8040 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8041 IWineD3DDeviceImpl_SetStreamSource,
8042 IWineD3DDeviceImpl_GetStreamSource,
8043 IWineD3DDeviceImpl_SetStreamSourceFreq,
8044 IWineD3DDeviceImpl_GetStreamSourceFreq,
8045 IWineD3DDeviceImpl_SetTexture,
8046 IWineD3DDeviceImpl_GetTexture,
8047 IWineD3DDeviceImpl_SetTextureStageState,
8048 IWineD3DDeviceImpl_GetTextureStageState,
8049 IWineD3DDeviceImpl_SetTransform,
8050 IWineD3DDeviceImpl_GetTransform,
8051 IWineD3DDeviceImpl_SetVertexDeclaration,
8052 IWineD3DDeviceImpl_GetVertexDeclaration,
8053 IWineD3DDeviceImpl_SetVertexShader,
8054 IWineD3DDeviceImpl_GetVertexShader,
8055 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8056 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8057 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8058 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8059 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8060 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8061 IWineD3DDeviceImpl_SetViewport,
8062 IWineD3DDeviceImpl_GetViewport,
8063 IWineD3DDeviceImpl_MultiplyTransform,
8064 IWineD3DDeviceImpl_ValidateDevice,
8065 IWineD3DDeviceImpl_ProcessVertices,
8066 /*** State block ***/
8067 IWineD3DDeviceImpl_BeginStateBlock,
8068 IWineD3DDeviceImpl_EndStateBlock,
8069 /*** Scene management ***/
8070 IWineD3DDeviceImpl_BeginScene,
8071 IWineD3DDeviceImpl_EndScene,
8072 IWineD3DDeviceImpl_Present,
8073 IWineD3DDeviceImpl_Clear,
8074 IWineD3DDeviceImpl_ClearRendertargetView,
8075 /*** Drawing ***/
8076 IWineD3DDeviceImpl_SetPrimitiveType,
8077 IWineD3DDeviceImpl_GetPrimitiveType,
8078 IWineD3DDeviceImpl_DrawPrimitive,
8079 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8080 IWineD3DDeviceImpl_DrawPrimitiveUP,
8081 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8082 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8083 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8084 IWineD3DDeviceImpl_DrawRectPatch,
8085 IWineD3DDeviceImpl_DrawTriPatch,
8086 IWineD3DDeviceImpl_DeletePatch,
8087 IWineD3DDeviceImpl_ColorFill,
8088 IWineD3DDeviceImpl_UpdateTexture,
8089 IWineD3DDeviceImpl_UpdateSurface,
8090 IWineD3DDeviceImpl_GetFrontBufferData,
8091 /*** object tracking ***/
8092 IWineD3DDeviceImpl_ResourceReleased,
8093 IWineD3DDeviceImpl_EnumResources
8096 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8097 WINED3DRS_ALPHABLENDENABLE ,
8098 WINED3DRS_ALPHAFUNC ,
8099 WINED3DRS_ALPHAREF ,
8100 WINED3DRS_ALPHATESTENABLE ,
8101 WINED3DRS_BLENDOP ,
8102 WINED3DRS_COLORWRITEENABLE ,
8103 WINED3DRS_DESTBLEND ,
8104 WINED3DRS_DITHERENABLE ,
8105 WINED3DRS_FILLMODE ,
8106 WINED3DRS_FOGDENSITY ,
8107 WINED3DRS_FOGEND ,
8108 WINED3DRS_FOGSTART ,
8109 WINED3DRS_LASTPIXEL ,
8110 WINED3DRS_SHADEMODE ,
8111 WINED3DRS_SRCBLEND ,
8112 WINED3DRS_STENCILENABLE ,
8113 WINED3DRS_STENCILFAIL ,
8114 WINED3DRS_STENCILFUNC ,
8115 WINED3DRS_STENCILMASK ,
8116 WINED3DRS_STENCILPASS ,
8117 WINED3DRS_STENCILREF ,
8118 WINED3DRS_STENCILWRITEMASK ,
8119 WINED3DRS_STENCILZFAIL ,
8120 WINED3DRS_TEXTUREFACTOR ,
8121 WINED3DRS_WRAP0 ,
8122 WINED3DRS_WRAP1 ,
8123 WINED3DRS_WRAP2 ,
8124 WINED3DRS_WRAP3 ,
8125 WINED3DRS_WRAP4 ,
8126 WINED3DRS_WRAP5 ,
8127 WINED3DRS_WRAP6 ,
8128 WINED3DRS_WRAP7 ,
8129 WINED3DRS_ZENABLE ,
8130 WINED3DRS_ZFUNC ,
8131 WINED3DRS_ZWRITEENABLE
8134 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8135 WINED3DTSS_ALPHAARG0 ,
8136 WINED3DTSS_ALPHAARG1 ,
8137 WINED3DTSS_ALPHAARG2 ,
8138 WINED3DTSS_ALPHAOP ,
8139 WINED3DTSS_BUMPENVLOFFSET ,
8140 WINED3DTSS_BUMPENVLSCALE ,
8141 WINED3DTSS_BUMPENVMAT00 ,
8142 WINED3DTSS_BUMPENVMAT01 ,
8143 WINED3DTSS_BUMPENVMAT10 ,
8144 WINED3DTSS_BUMPENVMAT11 ,
8145 WINED3DTSS_COLORARG0 ,
8146 WINED3DTSS_COLORARG1 ,
8147 WINED3DTSS_COLORARG2 ,
8148 WINED3DTSS_COLOROP ,
8149 WINED3DTSS_RESULTARG ,
8150 WINED3DTSS_TEXCOORDINDEX ,
8151 WINED3DTSS_TEXTURETRANSFORMFLAGS
8154 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8155 WINED3DSAMP_ADDRESSU ,
8156 WINED3DSAMP_ADDRESSV ,
8157 WINED3DSAMP_ADDRESSW ,
8158 WINED3DSAMP_BORDERCOLOR ,
8159 WINED3DSAMP_MAGFILTER ,
8160 WINED3DSAMP_MINFILTER ,
8161 WINED3DSAMP_MIPFILTER ,
8162 WINED3DSAMP_MIPMAPLODBIAS ,
8163 WINED3DSAMP_MAXMIPLEVEL ,
8164 WINED3DSAMP_MAXANISOTROPY ,
8165 WINED3DSAMP_SRGBTEXTURE ,
8166 WINED3DSAMP_ELEMENTINDEX
8169 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8170 WINED3DRS_AMBIENT ,
8171 WINED3DRS_AMBIENTMATERIALSOURCE ,
8172 WINED3DRS_CLIPPING ,
8173 WINED3DRS_CLIPPLANEENABLE ,
8174 WINED3DRS_COLORVERTEX ,
8175 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8176 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8177 WINED3DRS_FOGDENSITY ,
8178 WINED3DRS_FOGEND ,
8179 WINED3DRS_FOGSTART ,
8180 WINED3DRS_FOGTABLEMODE ,
8181 WINED3DRS_FOGVERTEXMODE ,
8182 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8183 WINED3DRS_LIGHTING ,
8184 WINED3DRS_LOCALVIEWER ,
8185 WINED3DRS_MULTISAMPLEANTIALIAS ,
8186 WINED3DRS_MULTISAMPLEMASK ,
8187 WINED3DRS_NORMALIZENORMALS ,
8188 WINED3DRS_PATCHEDGESTYLE ,
8189 WINED3DRS_POINTSCALE_A ,
8190 WINED3DRS_POINTSCALE_B ,
8191 WINED3DRS_POINTSCALE_C ,
8192 WINED3DRS_POINTSCALEENABLE ,
8193 WINED3DRS_POINTSIZE ,
8194 WINED3DRS_POINTSIZE_MAX ,
8195 WINED3DRS_POINTSIZE_MIN ,
8196 WINED3DRS_POINTSPRITEENABLE ,
8197 WINED3DRS_RANGEFOGENABLE ,
8198 WINED3DRS_SPECULARMATERIALSOURCE ,
8199 WINED3DRS_TWEENFACTOR ,
8200 WINED3DRS_VERTEXBLEND ,
8201 WINED3DRS_CULLMODE ,
8202 WINED3DRS_FOGCOLOR
8205 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8206 WINED3DTSS_TEXCOORDINDEX ,
8207 WINED3DTSS_TEXTURETRANSFORMFLAGS
8210 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8211 WINED3DSAMP_DMAPOFFSET
8214 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8215 DWORD rep = This->StateTable[state].representative;
8216 DWORD idx;
8217 BYTE shift;
8218 UINT i;
8219 WineD3DContext *context;
8221 if(!rep) return;
8222 for(i = 0; i < This->numContexts; i++) {
8223 context = This->contexts[i];
8224 if(isStateDirty(context, rep)) continue;
8226 context->dirtyArray[context->numDirtyEntries++] = rep;
8227 idx = rep >> 5;
8228 shift = rep & 0x1f;
8229 context->isStateDirty[idx] |= (1 << shift);
8233 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8234 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8235 /* The drawable size of a pbuffer render target is the current pbuffer size
8237 *width = dev->pbufferWidth;
8238 *height = dev->pbufferHeight;
8241 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8242 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8244 *width = This->pow2Width;
8245 *height = This->pow2Height;
8248 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8249 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8250 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8251 * current context's drawable, which is the size of the back buffer of the swapchain
8252 * the active context belongs to. The back buffer of the swapchain is stored as the
8253 * surface the context belongs to.
8255 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8256 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;