push 0a0aa53cd365a71ca6121b6df157ca635450378f
[wine/hacks.git] / dlls / wined3d / device.c
blobbb8b9759cb4995cd49d55859bca715f686f5b884
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 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
59 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
60 * actually have the same values in GL and D3D. */
61 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
63 switch(primitive_type)
65 case WINED3DPT_POINTLIST:
66 return GL_POINTS;
68 case WINED3DPT_LINELIST:
69 return GL_LINES;
71 case WINED3DPT_LINESTRIP:
72 return GL_LINE_STRIP;
74 case WINED3DPT_TRIANGLELIST:
75 return GL_TRIANGLES;
77 case WINED3DPT_TRIANGLESTRIP:
78 return GL_TRIANGLE_STRIP;
80 case WINED3DPT_TRIANGLEFAN:
81 return GL_TRIANGLE_FAN;
83 case WINED3DPT_LINELIST_ADJ:
84 return GL_LINES_ADJACENCY_ARB;
86 case WINED3DPT_LINESTRIP_ADJ:
87 return GL_LINE_STRIP_ADJACENCY_ARB;
89 case WINED3DPT_TRIANGLELIST_ADJ:
90 return GL_TRIANGLES_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLESTRIP_ADJ:
93 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
95 default:
96 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
97 return GL_NONE;
101 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
103 switch(primitive_type)
105 case GL_POINTS:
106 return WINED3DPT_POINTLIST;
108 case GL_LINES:
109 return WINED3DPT_LINELIST;
111 case GL_LINE_STRIP:
112 return WINED3DPT_LINESTRIP;
114 case GL_TRIANGLES:
115 return WINED3DPT_TRIANGLELIST;
117 case GL_TRIANGLE_STRIP:
118 return WINED3DPT_TRIANGLESTRIP;
120 case GL_TRIANGLE_FAN:
121 return WINED3DPT_TRIANGLEFAN;
123 case GL_LINES_ADJACENCY_ARB:
124 return WINED3DPT_LINELIST_ADJ;
126 case GL_LINE_STRIP_ADJACENCY_ARB:
127 return WINED3DPT_LINESTRIP_ADJ;
129 case GL_TRIANGLES_ADJACENCY_ARB:
130 return WINED3DPT_TRIANGLELIST_ADJ;
132 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLESTRIP_ADJ;
135 default:
136 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
137 return WINED3DPT_UNDEFINED;
141 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
143 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
144 *regnum = WINED3D_FFP_POSITION;
145 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
146 *regnum = WINED3D_FFP_BLENDWEIGHT;
147 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
148 *regnum = WINED3D_FFP_BLENDINDICES;
149 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
150 *regnum = WINED3D_FFP_NORMAL;
151 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
152 *regnum = WINED3D_FFP_PSIZE;
153 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
154 *regnum = WINED3D_FFP_DIFFUSE;
155 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
156 *regnum = WINED3D_FFP_SPECULAR;
157 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
158 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
159 else
161 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
162 *regnum = ~0U;
163 return FALSE;
166 return TRUE;
169 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
170 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
172 /* We need to deal with frequency data! */
173 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
174 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
175 const DWORD *streams = declaration->streams;
176 unsigned int i;
178 memset(stream_info, 0, sizeof(*stream_info));
180 /* Check for transformed vertices, disable vertex shader if present. */
181 stream_info->position_transformed = declaration->position_transformed;
182 if (declaration->position_transformed) use_vshader = FALSE;
184 /* Translate the declaration into strided data. */
185 for (i = 0; i < declaration->element_count; ++i)
187 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
188 GLuint buffer_object = 0;
189 const BYTE *data = NULL;
190 BOOL stride_used;
191 unsigned int idx;
192 DWORD stride;
194 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
195 element, i + 1, declaration->element_count);
197 if (!This->stateBlock->streamSource[element->input_slot]) continue;
199 stride = This->stateBlock->streamStride[element->input_slot];
200 if (This->stateBlock->streamIsUP)
202 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
203 buffer_object = 0;
204 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
206 else
208 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
209 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
211 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
212 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
213 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
214 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
215 * not, drawStridedSlow is needed, including a vertex buffer path. */
216 if (This->stateBlock->loadBaseVertexIndex < 0)
218 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
219 buffer_object = 0;
220 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
221 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
223 FIXME("System memory vertex data load offset is negative!\n");
227 if (fixup)
229 if (buffer_object) *fixup = TRUE;
230 else if (*fixup && !use_vshader
231 && (element->usage == WINED3DDECLUSAGE_COLOR
232 || element->usage == WINED3DDECLUSAGE_POSITIONT))
234 static BOOL warned = FALSE;
235 if (!warned)
237 /* This may be bad with the fixed function pipeline. */
238 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
239 warned = TRUE;
244 data += element->offset;
246 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
248 if (use_vshader)
250 if (element->output_slot == ~0U)
252 /* TODO: Assuming vertexdeclarations are usually used with the
253 * same or a similar shader, it might be worth it to store the
254 * last used output slot and try that one first. */
255 stride_used = vshader_get_input(This->stateBlock->vertexShader,
256 element->usage, element->usage_idx, &idx);
258 else
260 idx = element->output_slot;
261 stride_used = TRUE;
264 else
266 if (!element->ffp_valid)
268 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
269 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
270 stride_used = FALSE;
272 else
274 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
278 if (stride_used)
280 TRACE("Load %s array %u [usage %s, usage_idx %u, "
281 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
282 use_vshader ? "shader": "fixed function", idx,
283 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
284 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
286 stream_info->elements[idx].format_desc = element->format_desc;
287 stream_info->elements[idx].stride = stride;
288 stream_info->elements[idx].data = data;
289 stream_info->elements[idx].stream_idx = element->input_slot;
290 stream_info->elements[idx].buffer_object = buffer_object;
292 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
294 stream_info->swizzle_map |= 1 << idx;
296 stream_info->use_map |= 1 << idx;
300 /* Now call PreLoad on all the vertex buffers. In the very rare case
301 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
302 * The vertex buffer can now use the strided structure in the device instead of finding its
303 * own again.
305 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
306 * once in there. */
307 for (i = 0; i < stream_count; ++i)
309 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
310 if (vb) IWineD3DBuffer_PreLoad(vb);
314 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
315 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
317 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
318 e->format_desc = format_desc;
319 e->stride = strided->dwStride;
320 e->data = strided->lpData;
321 e->stream_idx = 0;
322 e->buffer_object = 0;
325 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
326 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
328 unsigned int i;
330 memset(stream_info, 0, sizeof(*stream_info));
332 if (strided->position.lpData)
333 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
334 if (strided->normal.lpData)
335 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
336 if (strided->diffuse.lpData)
337 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
338 if (strided->specular.lpData)
339 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
341 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
343 if (strided->texCoords[i].lpData)
344 stream_info_element_from_strided(This, &strided->texCoords[i],
345 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
348 stream_info->position_transformed = strided->position_transformed;
350 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
352 if (!stream_info->elements[i].format_desc) continue;
354 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
356 stream_info->swizzle_map |= 1 << i;
358 stream_info->use_map |= 1 << i;
362 /**********************************************************
363 * IUnknown parts follows
364 **********************************************************/
366 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
370 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
371 if (IsEqualGUID(riid, &IID_IUnknown)
372 || IsEqualGUID(riid, &IID_IWineD3DBase)
373 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
374 IUnknown_AddRef(iface);
375 *ppobj = This;
376 return S_OK;
378 *ppobj = NULL;
379 return E_NOINTERFACE;
382 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
384 ULONG refCount = InterlockedIncrement(&This->ref);
386 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
387 return refCount;
390 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
392 ULONG refCount = InterlockedDecrement(&This->ref);
394 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
396 if (!refCount) {
397 UINT i;
399 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
400 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
401 This->multistate_funcs[i] = NULL;
404 /* TODO: Clean up all the surfaces and textures! */
405 /* NOTE: You must release the parent if the object was created via a callback
406 ** ***************************/
408 if (!list_empty(&This->resources)) {
409 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
410 dumpResources(&This->resources);
413 if(This->contexts) ERR("Context array not freed!\n");
414 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
415 This->haveHardwareCursor = FALSE;
417 IWineD3D_Release(This->wineD3D);
418 This->wineD3D = NULL;
419 HeapFree(GetProcessHeap(), 0, This);
420 TRACE("Freed device %p\n", This);
421 This = NULL;
423 return refCount;
426 /**********************************************************
427 * IWineD3DDevice implementation follows
428 **********************************************************/
429 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
431 *pParent = This->parent;
432 IUnknown_AddRef(This->parent);
433 return WINED3D_OK;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
437 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
441 struct wined3d_buffer *object;
442 HRESULT hr;
444 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
446 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
447 if (!object)
449 ERR("Failed to allocate memory\n");
450 return E_OUTOFMEMORY;
453 object->vtbl = &wined3d_buffer_vtbl;
454 object->desc = *desc;
456 FIXME("Ignoring access flags (pool)\n");
458 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
459 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
460 if (FAILED(hr))
462 WARN("Failed to initialize resource, returning %#x\n", hr);
463 HeapFree(GetProcessHeap(), 0, object);
464 return hr;
466 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
468 TRACE("Created resource %p\n", object);
470 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
471 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
473 if (data)
475 BYTE *ptr;
477 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
478 if (FAILED(hr))
480 ERR("Failed to map buffer, hr %#x\n", hr);
481 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
482 return hr;
485 memcpy(ptr, data, desc->byte_width);
487 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
488 if (FAILED(hr))
490 ERR("Failed to unmap buffer, hr %#x\n", hr);
491 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
492 return hr;
496 *buffer = (IWineD3DBuffer *)object;
498 return WINED3D_OK;
501 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
502 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
505 /* Dummy format for now */
506 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
507 struct wined3d_buffer *object;
508 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
509 HRESULT hr;
510 BOOL conv;
512 if(Size == 0) {
513 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
514 *ppVertexBuffer = NULL;
515 return WINED3DERR_INVALIDCALL;
516 } else if(Pool == WINED3DPOOL_SCRATCH) {
517 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
518 * anyway, SCRATCH vertex buffers aren't usable anywhere
520 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
521 *ppVertexBuffer = NULL;
522 return WINED3DERR_INVALIDCALL;
525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
526 if (!object)
528 ERR("Out of memory\n");
529 *ppVertexBuffer = NULL;
530 return WINED3DERR_OUTOFVIDEOMEMORY;
533 object->vtbl = &wined3d_buffer_vtbl;
534 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
535 if (FAILED(hr))
537 WARN("Failed to initialize resource, returning %#x\n", hr);
538 HeapFree(GetProcessHeap(), 0, object);
539 *ppVertexBuffer = NULL;
540 return hr;
542 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
544 TRACE("(%p) : Created resource %p\n", This, object);
546 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);
547 *ppVertexBuffer = (IWineD3DBuffer *)object;
549 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
550 * drawStridedFast (half-life 2).
552 * Basically converting the vertices in the buffer is quite expensive, and observations
553 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
554 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
556 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
557 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
558 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
559 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
560 * dx7 apps.
561 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
562 * more. In this call we can convert dx7 buffers too.
564 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
565 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
566 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
567 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
568 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
569 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
570 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
571 } else if(dxVersion <= 7 && conv) {
572 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
573 } else {
574 object->flags |= WINED3D_BUFFER_CREATEBO;
576 return WINED3D_OK;
579 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
580 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
583 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
584 struct wined3d_buffer *object;
585 HRESULT hr;
587 TRACE("(%p) Creating index buffer\n", This);
589 /* Allocate the storage for the device */
590 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
591 if (!object)
593 ERR("Out of memory\n");
594 *ppIndexBuffer = NULL;
595 return WINED3DERR_OUTOFVIDEOMEMORY;
598 object->vtbl = &wined3d_buffer_vtbl;
599 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
600 if (FAILED(hr))
602 WARN("Failed to initialize resource, returning %#x\n", hr);
603 HeapFree(GetProcessHeap(), 0, object);
604 *ppIndexBuffer = NULL;
605 return hr;
607 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
609 TRACE("(%p) : Created resource %p\n", This, object);
611 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
612 object->flags |= WINED3D_BUFFER_CREATEBO;
615 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
616 Pool, object, object->resource.allocatedMemory);
617 *ppIndexBuffer = (IWineD3DBuffer *) object;
619 return WINED3D_OK;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DStateBlockImpl *object;
626 unsigned int i, j;
627 HRESULT temp_result;
629 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
630 if(!object)
632 ERR("Out of memory\n");
633 *ppStateBlock = NULL;
634 return WINED3DERR_OUTOFVIDEOMEMORY;
637 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
638 object->wineD3DDevice = This;
639 object->parent = parent;
640 object->ref = 1;
641 object->blockType = Type;
643 *ppStateBlock = (IWineD3DStateBlock *)object;
645 for(i = 0; i < LIGHTMAP_SIZE; i++) {
646 list_init(&object->lightMap[i]);
649 temp_result = allocate_shader_constants(object);
650 if (FAILED(temp_result))
652 HeapFree(GetProcessHeap(), 0, object);
653 return temp_result;
656 /* Special case - Used during initialization to produce a placeholder stateblock
657 so other functions called can update a state block */
658 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
660 /* Don't bother increasing the reference count otherwise a device will never
661 be freed due to circular dependencies */
662 return WINED3D_OK;
665 /* Otherwise, might as well set the whole state block to the appropriate values */
666 if (This->stateBlock != NULL)
667 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
668 else
669 memset(object->streamFreq, 1, sizeof(object->streamFreq));
671 /* Reset the ref and type after kludging it */
672 object->wineD3DDevice = This;
673 object->ref = 1;
674 object->blockType = Type;
676 TRACE("Updating changed flags appropriate for type %d\n", Type);
678 if (Type == WINED3DSBT_ALL) {
680 TRACE("ALL => Pretend everything has changed\n");
681 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
683 /* Lights are not part of the changed / set structure */
684 for(j = 0; j < LIGHTMAP_SIZE; j++) {
685 struct list *e;
686 LIST_FOR_EACH(e, &object->lightMap[j]) {
687 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
688 light->changed = TRUE;
689 light->enabledChanged = TRUE;
692 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
693 object->contained_render_states[j - 1] = j;
695 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
696 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
697 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
698 object->contained_transform_states[j - 1] = j;
700 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
701 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
702 object->contained_vs_consts_f[j] = j;
704 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
705 for(j = 0; j < MAX_CONST_I; j++) {
706 object->contained_vs_consts_i[j] = j;
708 object->num_contained_vs_consts_i = MAX_CONST_I;
709 for(j = 0; j < MAX_CONST_B; j++) {
710 object->contained_vs_consts_b[j] = j;
712 object->num_contained_vs_consts_b = MAX_CONST_B;
713 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
714 object->contained_ps_consts_f[j] = j;
716 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
717 for(j = 0; j < MAX_CONST_I; j++) {
718 object->contained_ps_consts_i[j] = j;
720 object->num_contained_ps_consts_i = MAX_CONST_I;
721 for(j = 0; j < MAX_CONST_B; j++) {
722 object->contained_ps_consts_b[j] = j;
724 object->num_contained_ps_consts_b = MAX_CONST_B;
725 for(i = 0; i < MAX_TEXTURES; i++) {
726 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
728 object->contained_tss_states[object->num_contained_tss_states].stage = i;
729 object->contained_tss_states[object->num_contained_tss_states].state = j;
730 object->num_contained_tss_states++;
733 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
734 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
735 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
736 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
737 object->num_contained_sampler_states++;
741 for(i = 0; i < MAX_STREAMS; i++) {
742 if(object->streamSource[i]) {
743 IWineD3DBuffer_AddRef(object->streamSource[i]);
746 if(object->pIndexData) {
747 IWineD3DBuffer_AddRef(object->pIndexData);
749 if(object->vertexShader) {
750 IWineD3DVertexShader_AddRef(object->vertexShader);
752 if(object->pixelShader) {
753 IWineD3DPixelShader_AddRef(object->pixelShader);
756 } else if (Type == WINED3DSBT_PIXELSTATE) {
758 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
759 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
761 object->changed.pixelShader = TRUE;
763 /* Pixel Shader Constants */
764 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
765 object->contained_ps_consts_f[i] = i;
766 object->changed.pixelShaderConstantsF[i] = TRUE;
768 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
769 for (i = 0; i < MAX_CONST_B; ++i) {
770 object->contained_ps_consts_b[i] = i;
771 object->changed.pixelShaderConstantsB |= (1 << i);
773 object->num_contained_ps_consts_b = MAX_CONST_B;
774 for (i = 0; i < MAX_CONST_I; ++i) {
775 object->contained_ps_consts_i[i] = i;
776 object->changed.pixelShaderConstantsI |= (1 << i);
778 object->num_contained_ps_consts_i = MAX_CONST_I;
780 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
781 DWORD rs = SavedPixelStates_R[i];
782 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
783 object->contained_render_states[i] = rs;
785 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
786 for (j = 0; j < MAX_TEXTURES; j++) {
787 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
788 DWORD state = SavedPixelStates_T[i];
789 object->changed.textureState[j] |= 1 << state;
790 object->contained_tss_states[object->num_contained_tss_states].stage = j;
791 object->contained_tss_states[object->num_contained_tss_states].state = state;
792 object->num_contained_tss_states++;
795 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
796 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
797 DWORD state = SavedPixelStates_S[i];
798 object->changed.samplerState[j] |= 1 << state;
799 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
800 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
801 object->num_contained_sampler_states++;
804 if(object->pixelShader) {
805 IWineD3DPixelShader_AddRef(object->pixelShader);
808 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
809 * on them. This makes releasing the buffer easier
811 for(i = 0; i < MAX_STREAMS; i++) {
812 object->streamSource[i] = NULL;
814 object->pIndexData = NULL;
815 object->vertexShader = NULL;
817 } else if (Type == WINED3DSBT_VERTEXSTATE) {
819 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
820 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
822 object->changed.vertexShader = TRUE;
824 /* Vertex Shader Constants */
825 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
826 object->changed.vertexShaderConstantsF[i] = TRUE;
827 object->contained_vs_consts_f[i] = i;
829 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
830 for (i = 0; i < MAX_CONST_B; ++i) {
831 object->contained_vs_consts_b[i] = i;
832 object->changed.vertexShaderConstantsB |= (1 << i);
834 object->num_contained_vs_consts_b = MAX_CONST_B;
835 for (i = 0; i < MAX_CONST_I; ++i) {
836 object->contained_vs_consts_i[i] = i;
837 object->changed.vertexShaderConstantsI |= (1 << i);
839 object->num_contained_vs_consts_i = MAX_CONST_I;
840 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
841 DWORD rs = SavedVertexStates_R[i];
842 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
843 object->contained_render_states[i] = rs;
845 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
846 for (j = 0; j < MAX_TEXTURES; j++) {
847 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
848 DWORD state = SavedVertexStates_T[i];
849 object->changed.textureState[j] |= 1 << state;
850 object->contained_tss_states[object->num_contained_tss_states].stage = j;
851 object->contained_tss_states[object->num_contained_tss_states].state = state;
852 object->num_contained_tss_states++;
855 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
856 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
857 DWORD state = SavedVertexStates_S[i];
858 object->changed.samplerState[j] |= 1 << state;
859 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
860 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
861 object->num_contained_sampler_states++;
865 for(j = 0; j < LIGHTMAP_SIZE; j++) {
866 struct list *e;
867 LIST_FOR_EACH(e, &object->lightMap[j]) {
868 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
869 light->changed = TRUE;
870 light->enabledChanged = TRUE;
874 for(i = 0; i < MAX_STREAMS; i++) {
875 if(object->streamSource[i]) {
876 IWineD3DBuffer_AddRef(object->streamSource[i]);
879 if(object->vertexShader) {
880 IWineD3DVertexShader_AddRef(object->vertexShader);
882 object->pIndexData = NULL;
883 object->pixelShader = NULL;
884 } else {
885 FIXME("Unrecognized state block type %d\n", Type);
888 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
889 return WINED3D_OK;
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
893 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
894 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
895 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
899 unsigned int Size = 1;
900 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
901 UINT mul_4w, mul_4h;
902 HRESULT hr;
904 TRACE("(%p) Create surface\n",This);
906 if(MultisampleQuality > 0) {
907 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
908 MultisampleQuality=0;
911 /** FIXME: Check that the format is supported
912 * by the device.
913 *******************************/
915 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
916 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
917 * space!
918 *********************************/
919 mul_4w = (Width + 3) & ~3;
920 mul_4h = (Height + 3) & ~3;
921 if (WINED3DFMT_UNKNOWN == Format) {
922 Size = 0;
923 } else if (Format == WINED3DFMT_DXT1) {
924 /* DXT1 is half byte per pixel */
925 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
927 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
928 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
929 Format == WINED3DFMT_ATI2N) {
930 Size = (mul_4w * glDesc->byte_count * mul_4h);
931 } else {
932 /* The pitch is a multiple of 4 bytes */
933 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
934 Size *= Height;
937 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
939 /** Create and initialise the surface resource **/
940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
941 if (!object)
943 ERR("Out of memory\n");
944 *ppSurface = NULL;
945 return WINED3DERR_OUTOFVIDEOMEMORY;
948 /* Look at the implementation and set the correct Vtable */
949 switch(Impl)
951 case SURFACE_OPENGL:
952 /* Check if a 3D adapter is available when creating gl surfaces */
953 if (!This->adapter)
955 ERR("OpenGL surfaces are not available without opengl\n");
956 HeapFree(GetProcessHeap(), 0, object);
957 return WINED3DERR_NOTAVAILABLE;
959 object->lpVtbl = &IWineD3DSurface_Vtbl;
960 break;
962 case SURFACE_GDI:
963 object->lpVtbl = &IWineGDISurface_Vtbl;
964 break;
966 default:
967 /* To be sure to catch this */
968 ERR("Unknown requested surface implementation %d!\n", Impl);
969 HeapFree(GetProcessHeap(), 0, object);
970 return WINED3DERR_INVALIDCALL;
973 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
974 if (FAILED(hr))
976 WARN("Failed to initialize resource, returning %#x\n", hr);
977 HeapFree(GetProcessHeap(), 0, object);
978 *ppSurface = NULL;
979 return hr;
982 TRACE("(%p) : Created resource %p\n", This, object);
984 *ppSurface = (IWineD3DSurface *)object;
986 /* "Standalone" surface */
987 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
989 object->currentDesc.Width = Width;
990 object->currentDesc.Height = Height;
991 object->currentDesc.MultiSampleType = MultiSample;
992 object->currentDesc.MultiSampleQuality = MultisampleQuality;
993 object->glDescription.level = Level;
994 list_init(&object->overlays);
996 /* Flags */
997 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
998 object->Flags |= Discard ? SFLAG_DISCARD : 0;
999 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1000 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1002 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1004 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1005 * this function is too deep to need to care about things like this.
1006 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1007 * ****************************************/
1008 switch(Pool) {
1009 case WINED3DPOOL_SCRATCH:
1010 if(!Lockable)
1011 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1012 "which are mutually exclusive, setting lockable to TRUE\n");
1013 Lockable = TRUE;
1014 break;
1015 case WINED3DPOOL_SYSTEMMEM:
1016 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1017 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1018 case WINED3DPOOL_MANAGED:
1019 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1020 "Usage of DYNAMIC which are mutually exclusive, not doing "
1021 "anything just telling you.\n");
1022 break;
1023 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1024 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1025 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1026 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1027 break;
1028 default:
1029 FIXME("(%p) Unknown pool %d\n", This, Pool);
1030 break;
1033 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1034 FIXME("Trying to create a render target that isn't in the default pool\n");
1037 /* mark the texture as dirty so that it gets loaded first time around*/
1038 surface_add_dirty_rect(*ppSurface, NULL);
1039 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1040 This, Width, Height, Format, debug_d3dformat(Format),
1041 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1043 list_init(&object->renderbuffers);
1045 /* Call the private setup routine */
1046 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1047 if (FAILED(hr))
1049 ERR("Private setup failed, returning %#x\n", hr);
1050 IWineD3DSurface_Release(*ppSurface);
1051 *ppSurface = NULL;
1052 return hr;
1055 return hr;
1058 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1059 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1061 struct wined3d_rendertarget_view *object;
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 if (!object)
1066 ERR("Failed to allocate memory\n");
1067 return E_OUTOFMEMORY;
1070 object->vtbl = &wined3d_rendertarget_view_vtbl;
1071 object->refcount = 1;
1072 IWineD3DResource_AddRef(resource);
1073 object->resource = resource;
1074 object->parent = parent;
1076 *rendertarget_view = (IWineD3DRendertargetView *)object;
1078 return WINED3D_OK;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1082 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1083 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1086 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1087 IWineD3DTextureImpl *object;
1088 unsigned int i;
1089 UINT tmpW;
1090 UINT tmpH;
1091 HRESULT hr;
1092 unsigned int pow2Width;
1093 unsigned int pow2Height;
1095 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1096 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1097 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1099 /* TODO: It should only be possible to create textures for formats
1100 that are reported as supported */
1101 if (WINED3DFMT_UNKNOWN >= Format) {
1102 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1103 return WINED3DERR_INVALIDCALL;
1106 /* Non-power2 support */
1107 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1109 pow2Width = Width;
1110 pow2Height = Height;
1112 else
1114 /* Find the nearest pow2 match */
1115 pow2Width = pow2Height = 1;
1116 while (pow2Width < Width) pow2Width <<= 1;
1117 while (pow2Height < Height) pow2Height <<= 1;
1119 if (pow2Width != Width || pow2Height != Height)
1121 if (Levels > 1)
1123 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1124 return WINED3DERR_INVALIDCALL;
1126 Levels = 1;
1130 /* Calculate levels for mip mapping */
1131 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1133 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1135 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1136 return WINED3DERR_INVALIDCALL;
1139 if (Levels > 1)
1141 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1142 return WINED3DERR_INVALIDCALL;
1145 Levels = 1;
1147 else if (!Levels)
1149 Levels = wined3d_log2i(max(Width, Height)) + 1;
1150 TRACE("Calculated levels = %d\n", Levels);
1153 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1154 if (!object)
1156 ERR("Out of memory\n");
1157 *ppTexture = NULL;
1158 return WINED3DERR_OUTOFVIDEOMEMORY;
1161 object->lpVtbl = &IWineD3DTexture_Vtbl;
1162 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1163 if (FAILED(hr))
1165 WARN("Failed to initialize resource, returning %#x\n", hr);
1166 HeapFree(GetProcessHeap(), 0, object);
1167 *ppTexture = NULL;
1168 return hr;
1171 TRACE("(%p) : Created resource %p\n", This, object);
1173 *ppTexture = (IWineD3DTexture *)object;
1175 basetexture_init(&object->baseTexture, Levels, Usage);
1177 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1179 object->baseTexture.minMipLookup = minMipLookup;
1180 object->baseTexture.magLookup = magLookup;
1181 } else {
1182 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1183 object->baseTexture.magLookup = magLookup_noFilter;
1186 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1187 /* Precalculated scaling for 'faked' non power of two texture coords.
1188 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1189 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1190 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1192 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1193 object->baseTexture.pow2Matrix[0] = 1.0;
1194 object->baseTexture.pow2Matrix[5] = 1.0;
1195 object->baseTexture.pow2Matrix[10] = 1.0;
1196 object->baseTexture.pow2Matrix[15] = 1.0;
1197 object->target = GL_TEXTURE_2D;
1198 object->cond_np2 = TRUE;
1199 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1200 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1201 (Width != pow2Width || Height != pow2Height) &&
1202 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1204 if ((Width != 1) || (Height != 1)) {
1205 object->baseTexture.pow2Matrix_identity = FALSE;
1208 object->baseTexture.pow2Matrix[0] = (float)Width;
1209 object->baseTexture.pow2Matrix[5] = (float)Height;
1210 object->baseTexture.pow2Matrix[10] = 1.0;
1211 object->baseTexture.pow2Matrix[15] = 1.0;
1212 object->target = GL_TEXTURE_RECTANGLE_ARB;
1213 object->cond_np2 = TRUE;
1214 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1215 } else {
1216 if ((Width != pow2Width) || (Height != pow2Height)) {
1217 object->baseTexture.pow2Matrix_identity = FALSE;
1218 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1219 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1220 } else {
1221 object->baseTexture.pow2Matrix[0] = 1.0;
1222 object->baseTexture.pow2Matrix[5] = 1.0;
1225 object->baseTexture.pow2Matrix[10] = 1.0;
1226 object->baseTexture.pow2Matrix[15] = 1.0;
1227 object->target = GL_TEXTURE_2D;
1228 object->cond_np2 = FALSE;
1230 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1232 /* Generate all the surfaces */
1233 tmpW = Width;
1234 tmpH = Height;
1235 for (i = 0; i < object->baseTexture.levels; i++)
1237 /* use the callback to create the texture surface */
1238 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1239 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1240 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1241 FIXME("Failed to create surface %p\n", object);
1242 /* clean up */
1243 object->surfaces[i] = NULL;
1244 IWineD3DTexture_Release((IWineD3DTexture *)object);
1246 *ppTexture = NULL;
1247 return hr;
1250 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1251 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1252 surface_set_texture_target(object->surfaces[i], object->target);
1253 /* calculate the next mipmap level */
1254 tmpW = max(1, tmpW >> 1);
1255 tmpH = max(1, tmpH >> 1);
1257 object->baseTexture.internal_preload = texture_internal_preload;
1259 TRACE("(%p) : Created texture %p\n", This, object);
1260 return WINED3D_OK;
1263 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1264 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1265 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1268 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1269 IWineD3DVolumeTextureImpl *object;
1270 unsigned int i;
1271 UINT tmpW;
1272 UINT tmpH;
1273 UINT tmpD;
1274 HRESULT hr;
1276 /* TODO: It should only be possible to create textures for formats
1277 that are reported as supported */
1278 if (WINED3DFMT_UNKNOWN >= Format) {
1279 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1280 return WINED3DERR_INVALIDCALL;
1282 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1283 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1284 return WINED3DERR_INVALIDCALL;
1287 /* Calculate levels for mip mapping */
1288 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1290 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1292 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1293 return WINED3DERR_INVALIDCALL;
1296 if (Levels > 1)
1298 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1299 return WINED3DERR_INVALIDCALL;
1302 Levels = 1;
1304 else if (!Levels)
1306 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1307 TRACE("Calculated levels = %d\n", Levels);
1310 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1311 if (!object)
1313 ERR("Out of memory\n");
1314 *ppVolumeTexture = NULL;
1315 return WINED3DERR_OUTOFVIDEOMEMORY;
1318 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1319 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUMETEXTURE,
1320 This, 0, Usage, format_desc, Pool, parent);
1321 if (FAILED(hr))
1323 WARN("Failed to initialize resource, returning %#x\n", hr);
1324 HeapFree(GetProcessHeap(), 0, object);
1325 *ppVolumeTexture = NULL;
1326 return hr;
1329 TRACE("(%p) : Created resource %p\n", This, object);
1331 basetexture_init(&object->baseTexture, Levels, Usage);
1333 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1334 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1336 /* Is NP2 support for volumes needed? */
1337 object->baseTexture.pow2Matrix[ 0] = 1.0;
1338 object->baseTexture.pow2Matrix[ 5] = 1.0;
1339 object->baseTexture.pow2Matrix[10] = 1.0;
1340 object->baseTexture.pow2Matrix[15] = 1.0;
1342 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1344 object->baseTexture.minMipLookup = minMipLookup;
1345 object->baseTexture.magLookup = magLookup;
1346 } else {
1347 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1348 object->baseTexture.magLookup = magLookup_noFilter;
1351 /* Generate all the surfaces */
1352 tmpW = Width;
1353 tmpH = Height;
1354 tmpD = Depth;
1356 for (i = 0; i < object->baseTexture.levels; i++)
1358 HRESULT hr;
1359 /* Create the volume */
1360 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1361 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1362 if(FAILED(hr)) {
1363 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1364 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1365 *ppVolumeTexture = NULL;
1366 return hr;
1369 /* Set its container to this object */
1370 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1372 /* calculate the next mipmap level */
1373 tmpW = max(1, tmpW >> 1);
1374 tmpH = max(1, tmpH >> 1);
1375 tmpD = max(1, tmpD >> 1);
1377 object->baseTexture.internal_preload = volumetexture_internal_preload;
1379 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1380 TRACE("(%p) : Created volume texture %p\n", This, object);
1381 return WINED3D_OK;
1384 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1385 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1386 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1389 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1390 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1391 HRESULT hr;
1393 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1394 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1395 return WINED3DERR_INVALIDCALL;
1398 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1399 if (!object)
1401 ERR("Out of memory\n");
1402 *ppVolume = NULL;
1403 return WINED3DERR_OUTOFVIDEOMEMORY;
1406 object->lpVtbl = &IWineD3DVolume_Vtbl;
1407 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1408 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1409 if (FAILED(hr))
1411 WARN("Failed to initialize resource, returning %#x\n", hr);
1412 HeapFree(GetProcessHeap(), 0, object);
1413 *ppVolume = NULL;
1414 return hr;
1417 TRACE("(%p) : Created resource %p\n", This, object);
1419 *ppVolume = (IWineD3DVolume *)object;
1421 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1422 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1424 object->currentDesc.Width = Width;
1425 object->currentDesc.Height = Height;
1426 object->currentDesc.Depth = Depth;
1428 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1429 object->lockable = TRUE;
1430 object->locked = FALSE;
1431 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1432 object->dirty = TRUE;
1434 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1436 return WINED3D_OK;
1439 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1440 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1441 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1444 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1445 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1446 unsigned int i, j;
1447 UINT tmpW;
1448 HRESULT hr;
1449 unsigned int pow2EdgeLength;
1451 /* TODO: It should only be possible to create textures for formats
1452 that are reported as supported */
1453 if (WINED3DFMT_UNKNOWN >= Format) {
1454 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1455 return WINED3DERR_INVALIDCALL;
1458 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1459 WARN("(%p) : Tried to create not supported cube texture\n", This);
1460 return WINED3DERR_INVALIDCALL;
1463 /* Calculate levels for mip mapping */
1464 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1466 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1468 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1469 return WINED3DERR_INVALIDCALL;
1472 if (Levels > 1)
1474 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1475 return WINED3DERR_INVALIDCALL;
1478 Levels = 1;
1480 else if (!Levels)
1482 Levels = wined3d_log2i(EdgeLength) + 1;
1483 TRACE("Calculated levels = %d\n", Levels);
1486 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1487 if (!object)
1489 ERR("Out of memory\n");
1490 *ppCubeTexture = NULL;
1491 return WINED3DERR_OUTOFVIDEOMEMORY;
1494 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1495 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1496 if (FAILED(hr))
1498 WARN("Failed to initialize resource, returning %#x\n", hr);
1499 HeapFree(GetProcessHeap(), 0, object);
1500 *ppCubeTexture = NULL;
1501 return hr;
1504 TRACE("(%p) : Created resource %p\n", This, object);
1506 basetexture_init(&object->baseTexture, Levels, Usage);
1508 TRACE("(%p) Create Cube Texture\n", This);
1510 /* Find the nearest pow2 match */
1511 pow2EdgeLength = 1;
1512 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1514 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1515 /* Precalculated scaling for 'faked' non power of two texture coords */
1516 object->baseTexture.pow2Matrix[ 0] = 1.0;
1517 object->baseTexture.pow2Matrix[ 5] = 1.0;
1518 object->baseTexture.pow2Matrix[10] = 1.0;
1519 object->baseTexture.pow2Matrix[15] = 1.0;
1520 } else {
1521 /* Precalculated scaling for 'faked' non power of two texture coords */
1522 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1523 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1524 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1525 object->baseTexture.pow2Matrix[15] = 1.0;
1526 object->baseTexture.pow2Matrix_identity = FALSE;
1529 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1531 object->baseTexture.minMipLookup = minMipLookup;
1532 object->baseTexture.magLookup = magLookup;
1533 } else {
1534 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1535 object->baseTexture.magLookup = magLookup_noFilter;
1538 /* Generate all the surfaces */
1539 tmpW = EdgeLength;
1540 for (i = 0; i < object->baseTexture.levels; i++) {
1542 /* Create the 6 faces */
1543 for (j = 0; j < 6; j++) {
1544 static const GLenum cube_targets[6] = {
1545 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1546 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1547 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1548 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1549 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1550 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1553 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1554 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1555 if (FAILED(hr))
1557 FIXME("(%p) Failed to create surface\n",object);
1558 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1559 *ppCubeTexture = NULL;
1560 return hr;
1562 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1563 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1564 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1566 tmpW = max(1, tmpW >> 1);
1568 object->baseTexture.internal_preload = cubetexture_internal_preload;
1570 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1571 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1572 return WINED3D_OK;
1575 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1577 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1578 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1579 const IWineD3DQueryVtbl *vtable;
1581 /* Just a check to see if we support this type of query */
1582 switch(Type) {
1583 case WINED3DQUERYTYPE_OCCLUSION:
1584 TRACE("(%p) occlusion query\n", This);
1585 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1586 hr = WINED3D_OK;
1587 else
1588 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1590 vtable = &IWineD3DOcclusionQuery_Vtbl;
1591 break;
1593 case WINED3DQUERYTYPE_EVENT:
1594 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1595 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1596 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1598 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1600 vtable = &IWineD3DEventQuery_Vtbl;
1601 hr = WINED3D_OK;
1602 break;
1604 case WINED3DQUERYTYPE_VCACHE:
1605 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1606 case WINED3DQUERYTYPE_VERTEXSTATS:
1607 case WINED3DQUERYTYPE_TIMESTAMP:
1608 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1609 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1610 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1611 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1612 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1613 case WINED3DQUERYTYPE_PIXELTIMINGS:
1614 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1615 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1616 default:
1617 /* Use the base Query vtable until we have a special one for each query */
1618 vtable = &IWineD3DQuery_Vtbl;
1619 FIXME("(%p) Unhandled query type %d\n", This, Type);
1621 if(NULL == ppQuery || hr != WINED3D_OK) {
1622 return hr;
1625 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1626 if(!object)
1628 ERR("Out of memory\n");
1629 *ppQuery = NULL;
1630 return WINED3DERR_OUTOFVIDEOMEMORY;
1633 object->lpVtbl = vtable;
1634 object->type = Type;
1635 object->state = QUERY_CREATED;
1636 object->wineD3DDevice = This;
1637 object->parent = parent;
1638 object->ref = 1;
1640 *ppQuery = (IWineD3DQuery *)object;
1642 /* allocated the 'extended' data based on the type of query requested */
1643 switch(Type){
1644 case WINED3DQUERYTYPE_OCCLUSION:
1645 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1646 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1648 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1649 TRACE("(%p) Allocating data for an occlusion query\n", This);
1651 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1652 ENTER_GL();
1653 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1654 LEAVE_GL();
1655 break;
1657 case WINED3DQUERYTYPE_EVENT:
1658 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1659 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1661 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1662 ENTER_GL();
1663 if(GL_SUPPORT(APPLE_FENCE)) {
1664 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1665 checkGLcall("glGenFencesAPPLE");
1666 } else if(GL_SUPPORT(NV_FENCE)) {
1667 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1668 checkGLcall("glGenFencesNV");
1670 LEAVE_GL();
1671 break;
1673 case WINED3DQUERYTYPE_VCACHE:
1674 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1675 case WINED3DQUERYTYPE_VERTEXSTATS:
1676 case WINED3DQUERYTYPE_TIMESTAMP:
1677 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1678 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1679 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1680 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1681 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1682 case WINED3DQUERYTYPE_PIXELTIMINGS:
1683 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1684 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1685 default:
1686 object->extendedData = 0;
1687 FIXME("(%p) Unhandled query type %d\n",This , Type);
1689 TRACE("(%p) : Created Query %p\n", This, object);
1690 return WINED3D_OK;
1693 /*****************************************************************************
1694 * IWineD3DDeviceImpl_SetupFullscreenWindow
1696 * Helper function that modifies a HWND's Style and ExStyle for proper
1697 * fullscreen use.
1699 * Params:
1700 * iface: Pointer to the IWineD3DDevice interface
1701 * window: Window to setup
1703 *****************************************************************************/
1704 static LONG fullscreen_style(LONG orig_style) {
1705 LONG style = orig_style;
1706 style &= ~WS_CAPTION;
1707 style &= ~WS_THICKFRAME;
1709 /* Make sure the window is managed, otherwise we won't get keyboard input */
1710 style |= WS_POPUP | WS_SYSMENU;
1712 return style;
1715 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1716 LONG exStyle = orig_exStyle;
1718 /* Filter out window decorations */
1719 exStyle &= ~WS_EX_WINDOWEDGE;
1720 exStyle &= ~WS_EX_CLIENTEDGE;
1722 return exStyle;
1725 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1728 LONG style, exStyle;
1729 /* Don't do anything if an original style is stored.
1730 * That shouldn't happen
1732 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1733 if (This->style || This->exStyle) {
1734 ERR("(%p): Want to change the window parameters of HWND %p, but "
1735 "another style is stored for restoration afterwards\n", This, window);
1738 /* Get the parameters and save them */
1739 style = GetWindowLongW(window, GWL_STYLE);
1740 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1741 This->style = style;
1742 This->exStyle = exStyle;
1744 style = fullscreen_style(style);
1745 exStyle = fullscreen_exStyle(exStyle);
1747 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1748 This->style, This->exStyle, style, exStyle);
1750 SetWindowLongW(window, GWL_STYLE, style);
1751 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1753 /* Inform the window about the update. */
1754 SetWindowPos(window, HWND_TOP, 0, 0,
1755 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1758 /*****************************************************************************
1759 * IWineD3DDeviceImpl_RestoreWindow
1761 * Helper function that restores a windows' properties when taking it out
1762 * of fullscreen mode
1764 * Params:
1765 * iface: Pointer to the IWineD3DDevice interface
1766 * window: Window to setup
1768 *****************************************************************************/
1769 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1771 LONG style, exStyle;
1773 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1774 * switch, do nothing
1776 if (!This->style && !This->exStyle) return;
1778 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1779 This, window, This->style, This->exStyle);
1781 style = GetWindowLongW(window, GWL_STYLE);
1782 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1784 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1785 * Some applications change it before calling Reset() when switching between windowed and
1786 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1788 if(style == fullscreen_style(This->style) &&
1789 exStyle == fullscreen_style(This->exStyle)) {
1790 SetWindowLongW(window, GWL_STYLE, This->style);
1791 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1794 /* Delete the old values */
1795 This->style = 0;
1796 This->exStyle = 0;
1798 /* Inform the window about the update */
1799 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1800 0, 0, 0, 0, /* Pos, Size, ignored */
1801 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1804 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1805 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1806 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1807 IUnknown *parent, WINED3DSURFTYPE surface_type)
1809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1811 HDC hDc;
1812 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1813 HRESULT hr;
1814 IUnknown *bufferParent;
1815 BOOL displaymode_set = FALSE;
1816 WINED3DDISPLAYMODE Mode;
1817 const struct GlPixelFormatDesc *format_desc;
1819 TRACE("(%p) : Created Additional Swap Chain\n", This);
1821 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1822 * does a device hold a reference to a swap chain giving them a lifetime of the device
1823 * or does the swap chain notify the device of its destruction.
1824 *******************************/
1826 /* Check the params */
1827 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1828 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1829 return WINED3DERR_INVALIDCALL;
1830 } else if (pPresentationParameters->BackBufferCount > 1) {
1831 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");
1834 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1835 if(!object)
1837 ERR("Out of memory\n");
1838 *ppSwapChain = NULL;
1839 return WINED3DERR_OUTOFVIDEOMEMORY;
1842 switch(surface_type) {
1843 case SURFACE_GDI:
1844 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1845 break;
1846 case SURFACE_OPENGL:
1847 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1848 break;
1849 case SURFACE_UNKNOWN:
1850 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1851 HeapFree(GetProcessHeap(), 0, object);
1852 return WINED3DERR_INVALIDCALL;
1854 object->wineD3DDevice = This;
1855 object->parent = parent;
1856 object->ref = 1;
1858 *ppSwapChain = (IWineD3DSwapChain *)object;
1860 /*********************
1861 * Lookup the window Handle and the relating X window handle
1862 ********************/
1864 /* Setup hwnd we are using, plus which display this equates to */
1865 object->win_handle = pPresentationParameters->hDeviceWindow;
1866 if (!object->win_handle) {
1867 object->win_handle = This->createParms.hFocusWindow;
1869 if(!pPresentationParameters->Windowed && object->win_handle) {
1870 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1871 pPresentationParameters->BackBufferWidth,
1872 pPresentationParameters->BackBufferHeight);
1875 hDc = GetDC(object->win_handle);
1876 TRACE("Using hDc %p\n", hDc);
1878 if (NULL == hDc) {
1879 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1880 return WINED3DERR_NOTAVAILABLE;
1883 /* Get info on the current display setup */
1884 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1885 object->orig_width = Mode.Width;
1886 object->orig_height = Mode.Height;
1887 object->orig_fmt = Mode.Format;
1888 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1890 if (pPresentationParameters->Windowed &&
1891 ((pPresentationParameters->BackBufferWidth == 0) ||
1892 (pPresentationParameters->BackBufferHeight == 0) ||
1893 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1895 RECT Rect;
1896 GetClientRect(object->win_handle, &Rect);
1898 if (pPresentationParameters->BackBufferWidth == 0) {
1899 pPresentationParameters->BackBufferWidth = Rect.right;
1900 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1902 if (pPresentationParameters->BackBufferHeight == 0) {
1903 pPresentationParameters->BackBufferHeight = Rect.bottom;
1904 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1906 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1907 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1908 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1912 /* Put the correct figures in the presentation parameters */
1913 TRACE("Copying across presentation parameters\n");
1914 object->presentParms = *pPresentationParameters;
1916 TRACE("calling rendertarget CB\n");
1917 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1918 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1919 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1920 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1921 if (SUCCEEDED(hr)) {
1922 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1923 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1924 if(surface_type == SURFACE_OPENGL) {
1925 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1927 } else {
1928 ERR("Failed to create the front buffer\n");
1929 goto error;
1932 /*********************
1933 * Windowed / Fullscreen
1934 *******************/
1937 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1938 * so we should really check to see if there is a fullscreen swapchain already
1939 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1940 **************************************/
1942 if (!pPresentationParameters->Windowed) {
1943 WINED3DDISPLAYMODE mode;
1946 /* Change the display settings */
1947 mode.Width = pPresentationParameters->BackBufferWidth;
1948 mode.Height = pPresentationParameters->BackBufferHeight;
1949 mode.Format = pPresentationParameters->BackBufferFormat;
1950 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1952 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1953 displaymode_set = TRUE;
1957 * Create an opengl context for the display visual
1958 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1959 * use different properties after that point in time. FIXME: How to handle when requested format
1960 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1961 * it chooses is identical to the one already being used!
1962 **********************************/
1963 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1965 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1966 if(!object->context) {
1967 ERR("Failed to create the context array\n");
1968 hr = E_OUTOFMEMORY;
1969 goto error;
1971 object->num_contexts = 1;
1973 if(surface_type == SURFACE_OPENGL) {
1974 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1975 if (!object->context[0]) {
1976 ERR("Failed to create a new context\n");
1977 hr = WINED3DERR_NOTAVAILABLE;
1978 goto error;
1979 } else {
1980 TRACE("Context created (HWND=%p, glContext=%p)\n",
1981 object->win_handle, object->context[0]->glCtx);
1985 /*********************
1986 * Create the back, front and stencil buffers
1987 *******************/
1988 if(object->presentParms.BackBufferCount > 0) {
1989 UINT i;
1991 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1992 if(!object->backBuffer) {
1993 ERR("Out of memory\n");
1994 hr = E_OUTOFMEMORY;
1995 goto error;
1998 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1999 TRACE("calling rendertarget CB\n");
2000 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2001 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2002 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2003 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2004 if(SUCCEEDED(hr)) {
2005 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2006 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2007 } else {
2008 ERR("Cannot create new back buffer\n");
2009 goto error;
2011 if(surface_type == SURFACE_OPENGL) {
2012 ENTER_GL();
2013 glDrawBuffer(GL_BACK);
2014 checkGLcall("glDrawBuffer(GL_BACK)");
2015 LEAVE_GL();
2018 } else {
2019 object->backBuffer = NULL;
2021 /* Single buffering - draw to front buffer */
2022 if(surface_type == SURFACE_OPENGL) {
2023 ENTER_GL();
2024 glDrawBuffer(GL_FRONT);
2025 checkGLcall("glDrawBuffer(GL_FRONT)");
2026 LEAVE_GL();
2030 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2031 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2032 TRACE("Creating depth stencil buffer\n");
2033 if (This->auto_depth_stencil_buffer == NULL ) {
2034 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2035 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2036 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2037 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2038 &This->auto_depth_stencil_buffer);
2039 if (SUCCEEDED(hr)) {
2040 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2041 } else {
2042 ERR("Failed to create the auto depth stencil\n");
2043 goto error;
2048 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2050 TRACE("Created swapchain %p\n", object);
2051 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2052 return WINED3D_OK;
2054 error:
2055 if (displaymode_set) {
2056 DEVMODEW devmode;
2057 RECT clip_rc;
2059 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2060 ClipCursor(NULL);
2062 /* Change the display settings */
2063 memset(&devmode, 0, sizeof(devmode));
2064 devmode.dmSize = sizeof(devmode);
2065 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2066 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2067 devmode.dmPelsWidth = object->orig_width;
2068 devmode.dmPelsHeight = object->orig_height;
2069 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2072 if (object->backBuffer) {
2073 UINT i;
2074 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2075 if(object->backBuffer[i]) {
2076 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2077 IUnknown_Release(bufferParent); /* once for the get parent */
2078 if (IUnknown_Release(bufferParent) > 0) {
2079 FIXME("(%p) Something's still holding the back buffer\n",This);
2083 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2084 object->backBuffer = NULL;
2086 if(object->context && object->context[0])
2087 DestroyContext(This, object->context[0]);
2088 if(object->frontBuffer) {
2089 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2090 IUnknown_Release(bufferParent); /* once for the get parent */
2091 if (IUnknown_Release(bufferParent) > 0) {
2092 FIXME("(%p) Something's still holding the front buffer\n",This);
2095 HeapFree(GetProcessHeap(), 0, object);
2096 return hr;
2099 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2100 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2102 TRACE("(%p)\n", This);
2104 return This->NumberOfSwapChains;
2107 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2109 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2111 if(iSwapChain < This->NumberOfSwapChains) {
2112 *pSwapChain = This->swapchains[iSwapChain];
2113 IWineD3DSwapChain_AddRef(*pSwapChain);
2114 TRACE("(%p) returning %p\n", This, *pSwapChain);
2115 return WINED3D_OK;
2116 } else {
2117 TRACE("Swapchain out of range\n");
2118 *pSwapChain = NULL;
2119 return WINED3DERR_INVALIDCALL;
2123 /*****
2124 * Vertex Declaration
2125 *****/
2126 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2127 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2129 IWineD3DVertexDeclarationImpl *object = NULL;
2130 HRESULT hr = WINED3D_OK;
2132 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2133 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2135 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2136 if(!object)
2138 ERR("Out of memory\n");
2139 *ppVertexDeclaration = NULL;
2140 return WINED3DERR_OUTOFVIDEOMEMORY;
2143 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2144 object->wineD3DDevice = This;
2145 object->parent = parent;
2146 object->ref = 1;
2148 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2150 hr = vertexdeclaration_init(object, elements, element_count);
2152 if(FAILED(hr)) {
2153 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2154 *ppVertexDeclaration = NULL;
2157 return hr;
2160 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2161 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2163 unsigned int idx, idx2;
2164 unsigned int offset;
2165 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2166 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2167 BOOL has_blend_idx = has_blend &&
2168 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2169 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2170 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2171 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2172 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2173 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2174 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2176 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2177 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2178 WINED3DVERTEXELEMENT *elements = NULL;
2180 unsigned int size;
2181 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2182 if (has_blend_idx) num_blends--;
2184 /* Compute declaration size */
2185 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2186 has_psize + has_diffuse + has_specular + num_textures;
2188 /* convert the declaration */
2189 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2190 if (!elements) return ~0U;
2192 idx = 0;
2193 if (has_pos) {
2194 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2195 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2196 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2198 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2199 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2200 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2202 else {
2203 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2204 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2206 elements[idx].usage_idx = 0;
2207 idx++;
2209 if (has_blend && (num_blends > 0)) {
2210 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2211 elements[idx].format = WINED3DFMT_A8R8G8B8;
2212 else {
2213 switch(num_blends) {
2214 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2215 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2216 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2217 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2218 default:
2219 ERR("Unexpected amount of blend values: %u\n", num_blends);
2222 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2223 elements[idx].usage_idx = 0;
2224 idx++;
2226 if (has_blend_idx) {
2227 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2228 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2229 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2230 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2231 elements[idx].format = WINED3DFMT_A8R8G8B8;
2232 else
2233 elements[idx].format = WINED3DFMT_R32_FLOAT;
2234 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2235 elements[idx].usage_idx = 0;
2236 idx++;
2238 if (has_normal) {
2239 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2240 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2241 elements[idx].usage_idx = 0;
2242 idx++;
2244 if (has_psize) {
2245 elements[idx].format = WINED3DFMT_R32_FLOAT;
2246 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2247 elements[idx].usage_idx = 0;
2248 idx++;
2250 if (has_diffuse) {
2251 elements[idx].format = WINED3DFMT_A8R8G8B8;
2252 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2253 elements[idx].usage_idx = 0;
2254 idx++;
2256 if (has_specular) {
2257 elements[idx].format = WINED3DFMT_A8R8G8B8;
2258 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2259 elements[idx].usage_idx = 1;
2260 idx++;
2262 for (idx2 = 0; idx2 < num_textures; idx2++) {
2263 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2264 switch (numcoords) {
2265 case WINED3DFVF_TEXTUREFORMAT1:
2266 elements[idx].format = WINED3DFMT_R32_FLOAT;
2267 break;
2268 case WINED3DFVF_TEXTUREFORMAT2:
2269 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2270 break;
2271 case WINED3DFVF_TEXTUREFORMAT3:
2272 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2273 break;
2274 case WINED3DFVF_TEXTUREFORMAT4:
2275 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2276 break;
2278 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2279 elements[idx].usage_idx = idx2;
2280 idx++;
2283 /* Now compute offsets, and initialize the rest of the fields */
2284 for (idx = 0, offset = 0; idx < size; ++idx)
2286 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2287 elements[idx].input_slot = 0;
2288 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2289 elements[idx].offset = offset;
2290 offset += format_desc->component_count * format_desc->component_size;
2293 *ppVertexElements = elements;
2294 return size;
2297 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2298 WINED3DVERTEXELEMENT* elements = NULL;
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 unsigned int size;
2301 DWORD hr;
2303 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2304 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2306 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2307 HeapFree(GetProcessHeap(), 0, elements);
2308 if (hr != S_OK) return hr;
2310 return WINED3D_OK;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
2314 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2315 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2319 HRESULT hr = WINED3D_OK;
2321 if (!pFunction) return WINED3DERR_INVALIDCALL;
2323 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2324 if (!object)
2326 ERR("Out of memory\n");
2327 *ppVertexShader = NULL;
2328 return WINED3DERR_OUTOFVIDEOMEMORY;
2331 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2332 object->parent = parent;
2333 shader_init(&object->baseShader, iface);
2334 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2335 *ppVertexShader = (IWineD3DVertexShader *)object;
2337 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2339 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2340 if (FAILED(hr))
2342 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2343 IWineD3DVertexShader_Release(*ppVertexShader);
2344 *ppVertexShader = NULL;
2345 return hr;
2348 return hr;
2351 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2352 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2353 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2356 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2357 HRESULT hr = WINED3D_OK;
2359 if (!pFunction) return WINED3DERR_INVALIDCALL;
2361 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2362 if (!object)
2364 ERR("Out of memory\n");
2365 *ppPixelShader = NULL;
2366 return WINED3DERR_OUTOFVIDEOMEMORY;
2369 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2370 object->parent = parent;
2371 shader_init(&object->baseShader, iface);
2372 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2373 *ppPixelShader = (IWineD3DPixelShader *)object;
2375 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2377 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2378 if (FAILED(hr))
2380 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2381 IWineD3DPixelShader_Release(*ppPixelShader);
2382 *ppPixelShader = NULL;
2383 return hr;
2386 return hr;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2390 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2393 IWineD3DPaletteImpl *object;
2394 HRESULT hr;
2395 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2397 /* Create the new object */
2398 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2399 if(!object) {
2400 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2401 return E_OUTOFMEMORY;
2404 object->lpVtbl = &IWineD3DPalette_Vtbl;
2405 object->ref = 1;
2406 object->Flags = Flags;
2407 object->parent = Parent;
2408 object->wineD3DDevice = This;
2409 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2410 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2412 if(!object->hpal) {
2413 HeapFree( GetProcessHeap(), 0, object);
2414 return E_OUTOFMEMORY;
2417 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2418 if(FAILED(hr)) {
2419 IWineD3DPalette_Release((IWineD3DPalette *) object);
2420 return hr;
2423 *Palette = (IWineD3DPalette *) object;
2425 return WINED3D_OK;
2428 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2429 HBITMAP hbm;
2430 BITMAP bm;
2431 HRESULT hr;
2432 HDC dcb = NULL, dcs = NULL;
2433 WINEDDCOLORKEY colorkey;
2435 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2436 if(hbm)
2438 GetObjectA(hbm, sizeof(BITMAP), &bm);
2439 dcb = CreateCompatibleDC(NULL);
2440 if(!dcb) goto out;
2441 SelectObject(dcb, hbm);
2443 else
2445 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2446 * couldn't be loaded
2448 memset(&bm, 0, sizeof(bm));
2449 bm.bmWidth = 32;
2450 bm.bmHeight = 32;
2453 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2454 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2455 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2456 if(FAILED(hr)) {
2457 ERR("Wine logo requested, but failed to create surface\n");
2458 goto out;
2461 if(dcb) {
2462 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2463 if(FAILED(hr)) goto out;
2464 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2465 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2467 colorkey.dwColorSpaceLowValue = 0;
2468 colorkey.dwColorSpaceHighValue = 0;
2469 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2470 } else {
2471 /* Fill the surface with a white color to show that wined3d is there */
2472 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2475 out:
2476 if(dcb) {
2477 DeleteDC(dcb);
2479 if(hbm) {
2480 DeleteObject(hbm);
2482 return;
2485 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2486 unsigned int i;
2487 /* Under DirectX you can have texture stage operations even if no texture is
2488 bound, whereas opengl will only do texture operations when a valid texture is
2489 bound. We emulate this by creating dummy textures and binding them to each
2490 texture stage, but disable all stages by default. Hence if a stage is enabled
2491 then the default texture will kick in until replaced by a SetTexture call */
2492 ENTER_GL();
2494 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2495 /* The dummy texture does not have client storage backing */
2496 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2497 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2499 for (i = 0; i < GL_LIMITS(textures); i++) {
2500 GLubyte white = 255;
2502 /* Make appropriate texture active */
2503 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2504 checkGLcall("glActiveTextureARB");
2506 /* Generate an opengl texture name */
2507 glGenTextures(1, &This->dummyTextureName[i]);
2508 checkGLcall("glGenTextures");
2509 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2511 /* Generate a dummy 2d texture (not using 1d because they cause many
2512 * DRI drivers fall back to sw) */
2513 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2514 checkGLcall("glBindTexture");
2516 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2517 checkGLcall("glTexImage2D");
2519 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2520 /* Reenable because if supported it is enabled by default */
2521 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2522 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2525 LEAVE_GL();
2528 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2529 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2532 IWineD3DSwapChainImpl *swapchain = NULL;
2533 HRESULT hr;
2534 DWORD state;
2535 unsigned int i;
2537 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2539 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2540 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2542 /* TODO: Test if OpenGL is compiled in and loaded */
2544 TRACE("(%p) : Creating stateblock\n", This);
2545 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2546 hr = IWineD3DDevice_CreateStateBlock(iface,
2547 WINED3DSBT_INIT,
2548 (IWineD3DStateBlock **)&This->stateBlock,
2549 NULL);
2550 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2551 WARN("Failed to create stateblock\n");
2552 goto err_out;
2554 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2555 This->updateStateBlock = This->stateBlock;
2556 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2558 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2559 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2561 This->NumberOfPalettes = 1;
2562 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2563 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2564 ERR("Out of memory!\n");
2565 goto err_out;
2567 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2568 if(!This->palettes[0]) {
2569 ERR("Out of memory!\n");
2570 goto err_out;
2572 for (i = 0; i < 256; ++i) {
2573 This->palettes[0][i].peRed = 0xFF;
2574 This->palettes[0][i].peGreen = 0xFF;
2575 This->palettes[0][i].peBlue = 0xFF;
2576 This->palettes[0][i].peFlags = 0xFF;
2578 This->currentPalette = 0;
2580 /* Initialize the texture unit mapping to a 1:1 mapping */
2581 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2582 if (state < GL_LIMITS(fragment_samplers)) {
2583 This->texUnitMap[state] = state;
2584 This->rev_tex_unit_map[state] = state;
2585 } else {
2586 This->texUnitMap[state] = -1;
2587 This->rev_tex_unit_map[state] = -1;
2591 /* Setup the implicit swapchain */
2592 TRACE("Creating implicit swapchain\n");
2593 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2594 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2595 if (FAILED(hr))
2597 WARN("Failed to create implicit swapchain\n");
2598 goto err_out;
2601 This->NumberOfSwapChains = 1;
2602 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2603 if(!This->swapchains) {
2604 ERR("Out of memory!\n");
2605 goto err_out;
2607 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2609 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2610 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2611 This->render_targets[0] = swapchain->backBuffer[0];
2612 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2614 else {
2615 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2616 This->render_targets[0] = swapchain->frontBuffer;
2617 This->lastActiveRenderTarget = swapchain->frontBuffer;
2619 IWineD3DSurface_AddRef(This->render_targets[0]);
2620 This->activeContext = swapchain->context[0];
2621 This->lastThread = GetCurrentThreadId();
2623 /* Depth Stencil support */
2624 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2625 if (NULL != This->stencilBufferTarget) {
2626 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2629 hr = This->shader_backend->shader_alloc_private(iface);
2630 if(FAILED(hr)) {
2631 TRACE("Shader private data couldn't be allocated\n");
2632 goto err_out;
2634 hr = This->frag_pipe->alloc_private(iface);
2635 if(FAILED(hr)) {
2636 TRACE("Fragment pipeline private data couldn't be allocated\n");
2637 goto err_out;
2639 hr = This->blitter->alloc_private(iface);
2640 if(FAILED(hr)) {
2641 TRACE("Blitter private data couldn't be allocated\n");
2642 goto err_out;
2645 /* Set up some starting GL setup */
2647 /* Setup all the devices defaults */
2648 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2649 create_dummy_textures(This);
2651 ENTER_GL();
2653 /* Initialize the current view state */
2654 This->view_ident = 1;
2655 This->contexts[0]->last_was_rhw = 0;
2656 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2657 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2659 switch(wined3d_settings.offscreen_rendering_mode) {
2660 case ORM_FBO:
2661 case ORM_PBUFFER:
2662 This->offscreenBuffer = GL_BACK;
2663 break;
2665 case ORM_BACKBUFFER:
2667 if(This->activeContext->aux_buffers > 0) {
2668 TRACE("Using auxilliary buffer for offscreen rendering\n");
2669 This->offscreenBuffer = GL_AUX0;
2670 } else {
2671 TRACE("Using back buffer for offscreen rendering\n");
2672 This->offscreenBuffer = GL_BACK;
2677 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2678 LEAVE_GL();
2680 /* Clear the screen */
2681 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2682 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2683 0x00, 1.0, 0);
2685 This->d3d_initialized = TRUE;
2687 if(wined3d_settings.logo) {
2688 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2690 This->highest_dirty_ps_const = 0;
2691 This->highest_dirty_vs_const = 0;
2692 return WINED3D_OK;
2694 err_out:
2695 HeapFree(GetProcessHeap(), 0, This->render_targets);
2696 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2697 HeapFree(GetProcessHeap(), 0, This->swapchains);
2698 This->NumberOfSwapChains = 0;
2699 if(This->palettes) {
2700 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2701 HeapFree(GetProcessHeap(), 0, This->palettes);
2703 This->NumberOfPalettes = 0;
2704 if(swapchain) {
2705 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2707 if(This->stateBlock) {
2708 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2709 This->stateBlock = NULL;
2711 if (This->blit_priv) {
2712 This->blitter->free_private(iface);
2714 if (This->fragment_priv) {
2715 This->frag_pipe->free_private(iface);
2717 if (This->shader_priv) {
2718 This->shader_backend->shader_free_private(iface);
2720 return hr;
2723 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2724 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2727 IWineD3DSwapChainImpl *swapchain = NULL;
2728 HRESULT hr;
2730 /* Setup the implicit swapchain */
2731 TRACE("Creating implicit swapchain\n");
2732 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2733 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2734 if (FAILED(hr))
2736 WARN("Failed to create implicit swapchain\n");
2737 goto err_out;
2740 This->NumberOfSwapChains = 1;
2741 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2742 if(!This->swapchains) {
2743 ERR("Out of memory!\n");
2744 goto err_out;
2746 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2747 return WINED3D_OK;
2749 err_out:
2750 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2751 return hr;
2754 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2756 IWineD3DResource_UnLoad(resource);
2757 IWineD3DResource_Release(resource);
2758 return WINED3D_OK;
2761 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2763 int sampler;
2764 UINT i;
2765 TRACE("(%p)\n", This);
2767 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2769 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2770 * it was created. Thus make sure a context is active for the glDelete* calls
2772 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2774 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2776 /* Unload resources */
2777 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2779 TRACE("Deleting high order patches\n");
2780 for(i = 0; i < PATCHMAP_SIZE; i++) {
2781 struct list *e1, *e2;
2782 struct WineD3DRectPatch *patch;
2783 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2784 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2785 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2789 /* Delete the palette conversion shader if it is around */
2790 if(This->paletteConversionShader) {
2791 ENTER_GL();
2792 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2793 LEAVE_GL();
2794 This->paletteConversionShader = 0;
2797 /* Delete the pbuffer context if there is any */
2798 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2800 /* Delete the mouse cursor texture */
2801 if(This->cursorTexture) {
2802 ENTER_GL();
2803 glDeleteTextures(1, &This->cursorTexture);
2804 LEAVE_GL();
2805 This->cursorTexture = 0;
2808 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2809 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2811 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2812 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2815 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2816 * private data, it might contain opengl pointers
2818 if(This->depth_blt_texture) {
2819 ENTER_GL();
2820 glDeleteTextures(1, &This->depth_blt_texture);
2821 LEAVE_GL();
2822 This->depth_blt_texture = 0;
2824 if (This->depth_blt_rb) {
2825 ENTER_GL();
2826 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2827 LEAVE_GL();
2828 This->depth_blt_rb = 0;
2829 This->depth_blt_rb_w = 0;
2830 This->depth_blt_rb_h = 0;
2833 /* Release the update stateblock */
2834 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2835 if(This->updateStateBlock != This->stateBlock)
2836 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2838 This->updateStateBlock = NULL;
2840 { /* because were not doing proper internal refcounts releasing the primary state block
2841 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2842 to set this->stateBlock = NULL; first */
2843 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2844 This->stateBlock = NULL;
2846 /* Release the stateblock */
2847 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2848 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2852 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2853 This->blitter->free_private(iface);
2854 This->frag_pipe->free_private(iface);
2855 This->shader_backend->shader_free_private(iface);
2857 /* Release the buffers (with sanity checks)*/
2858 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2859 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2860 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2861 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2863 This->stencilBufferTarget = NULL;
2865 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2866 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2867 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2869 TRACE("Setting rendertarget to NULL\n");
2870 This->render_targets[0] = NULL;
2872 if (This->auto_depth_stencil_buffer) {
2873 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2874 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2876 This->auto_depth_stencil_buffer = NULL;
2879 for(i=0; i < This->NumberOfSwapChains; i++) {
2880 TRACE("Releasing the implicit swapchain %d\n", i);
2881 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2882 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2886 HeapFree(GetProcessHeap(), 0, This->swapchains);
2887 This->swapchains = NULL;
2888 This->NumberOfSwapChains = 0;
2890 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2891 HeapFree(GetProcessHeap(), 0, This->palettes);
2892 This->palettes = NULL;
2893 This->NumberOfPalettes = 0;
2895 HeapFree(GetProcessHeap(), 0, This->render_targets);
2896 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2897 This->render_targets = NULL;
2898 This->draw_buffers = NULL;
2900 This->d3d_initialized = FALSE;
2901 return WINED3D_OK;
2904 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2906 unsigned int i;
2908 for(i=0; i < This->NumberOfSwapChains; i++) {
2909 TRACE("Releasing the implicit swapchain %d\n", i);
2910 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2911 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2915 HeapFree(GetProcessHeap(), 0, This->swapchains);
2916 This->swapchains = NULL;
2917 This->NumberOfSwapChains = 0;
2918 return WINED3D_OK;
2921 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2922 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2923 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2925 * There is no way to deactivate thread safety once it is enabled.
2927 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2930 /*For now just store the flag(needed in case of ddraw) */
2931 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2933 return;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2937 const WINED3DDISPLAYMODE* pMode) {
2938 DEVMODEW devmode;
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 LONG ret;
2941 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2942 RECT clip_rc;
2944 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2946 /* Resize the screen even without a window:
2947 * The app could have unset it with SetCooperativeLevel, but not called
2948 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2949 * but we don't have any hwnd
2952 memset(&devmode, 0, sizeof(devmode));
2953 devmode.dmSize = sizeof(devmode);
2954 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2955 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2956 devmode.dmPelsWidth = pMode->Width;
2957 devmode.dmPelsHeight = pMode->Height;
2959 devmode.dmDisplayFrequency = pMode->RefreshRate;
2960 if (pMode->RefreshRate != 0) {
2961 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2964 /* Only change the mode if necessary */
2965 if( (This->ddraw_width == pMode->Width) &&
2966 (This->ddraw_height == pMode->Height) &&
2967 (This->ddraw_format == pMode->Format) &&
2968 (pMode->RefreshRate == 0) ) {
2969 return WINED3D_OK;
2972 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2973 if (ret != DISP_CHANGE_SUCCESSFUL) {
2974 if(devmode.dmDisplayFrequency != 0) {
2975 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2976 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2977 devmode.dmDisplayFrequency = 0;
2978 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2980 if(ret != DISP_CHANGE_SUCCESSFUL) {
2981 return WINED3DERR_NOTAVAILABLE;
2985 /* Store the new values */
2986 This->ddraw_width = pMode->Width;
2987 This->ddraw_height = pMode->Height;
2988 This->ddraw_format = pMode->Format;
2990 /* And finally clip mouse to our screen */
2991 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2992 ClipCursor(&clip_rc);
2994 return WINED3D_OK;
2997 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2999 *ppD3D= This->wineD3D;
3000 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3001 IWineD3D_AddRef(*ppD3D);
3002 return WINED3D_OK;
3005 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3008 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3009 (This->adapter->TextureRam/(1024*1024)),
3010 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3011 /* return simulated texture memory left */
3012 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3015 /*****
3016 * Get / Set Stream Source
3017 *****/
3018 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3019 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 IWineD3DBuffer *oldSrc;
3024 if (StreamNumber >= MAX_STREAMS) {
3025 WARN("Stream out of range %d\n", StreamNumber);
3026 return WINED3DERR_INVALIDCALL;
3027 } else if(OffsetInBytes & 0x3) {
3028 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3029 return WINED3DERR_INVALIDCALL;
3032 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3033 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3035 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3037 if(oldSrc == pStreamData &&
3038 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3039 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3040 TRACE("Application is setting the old values over, nothing to do\n");
3041 return WINED3D_OK;
3044 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3045 if (pStreamData) {
3046 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3047 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3050 /* Handle recording of state blocks */
3051 if (This->isRecordingState) {
3052 TRACE("Recording... not performing anything\n");
3053 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3054 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3055 return WINED3D_OK;
3058 if (pStreamData != NULL) {
3059 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3060 IWineD3DBuffer_AddRef(pStreamData);
3062 if (oldSrc != NULL) {
3063 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3064 IWineD3DBuffer_Release(oldSrc);
3067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3069 return WINED3D_OK;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3073 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3078 This->stateBlock->streamSource[StreamNumber],
3079 This->stateBlock->streamOffset[StreamNumber],
3080 This->stateBlock->streamStride[StreamNumber]);
3082 if (StreamNumber >= MAX_STREAMS) {
3083 WARN("Stream out of range %d\n", StreamNumber);
3084 return WINED3DERR_INVALIDCALL;
3086 *pStream = This->stateBlock->streamSource[StreamNumber];
3087 *pStride = This->stateBlock->streamStride[StreamNumber];
3088 if (pOffset) {
3089 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3092 if (*pStream != NULL) {
3093 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3101 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3103 /* Verify input at least in d3d9 this is invalid*/
3104 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3105 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3106 return WINED3DERR_INVALIDCALL;
3108 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3109 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3110 return WINED3DERR_INVALIDCALL;
3112 if( Divider == 0 ){
3113 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3114 return WINED3DERR_INVALIDCALL;
3117 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3118 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3120 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3121 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3123 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3124 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3128 return WINED3D_OK;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3135 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3137 TRACE("(%p) : returning %d\n", This, *Divider);
3139 return WINED3D_OK;
3142 /*****
3143 * Get / Set & Multiply Transform
3144 *****/
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 /* Most of this routine, comments included copied from ddraw tree initially: */
3149 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3151 /* Handle recording of state blocks */
3152 if (This->isRecordingState) {
3153 TRACE("Recording... not performing anything\n");
3154 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3155 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3156 return WINED3D_OK;
3160 * If the new matrix is the same as the current one,
3161 * we cut off any further processing. this seems to be a reasonable
3162 * optimization because as was noticed, some apps (warcraft3 for example)
3163 * tend towards setting the same matrix repeatedly for some reason.
3165 * From here on we assume that the new matrix is different, wherever it matters.
3167 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3168 TRACE("The app is setting the same matrix over again\n");
3169 return WINED3D_OK;
3170 } else {
3171 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3175 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3176 where ViewMat = Camera space, WorldMat = world space.
3178 In OpenGL, camera and world space is combined into GL_MODELVIEW
3179 matrix. The Projection matrix stay projection matrix.
3182 /* Capture the times we can just ignore the change for now */
3183 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3184 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3185 /* Handled by the state manager */
3188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3189 return WINED3D_OK;
3192 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3195 *pMatrix = This->stateBlock->transforms[State];
3196 return WINED3D_OK;
3199 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3200 const WINED3DMATRIX *mat = NULL;
3201 WINED3DMATRIX temp;
3203 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3204 * below means it will be recorded in a state block change, but it
3205 * works regardless where it is recorded.
3206 * If this is found to be wrong, change to StateBlock.
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3211 if (State <= HIGHEST_TRANSFORMSTATE)
3213 mat = &This->updateStateBlock->transforms[State];
3214 } else {
3215 FIXME("Unhandled transform state!!\n");
3218 multiply_matrix(&temp, mat, pMatrix);
3220 /* Apply change via set transform - will reapply to eg. lights this way */
3221 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3224 /*****
3225 * Get / Set Light
3226 *****/
3227 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3228 you can reference any indexes you want as long as that number max are enabled at any
3229 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3230 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3231 but when recording, just build a chain pretty much of commands to be replayed. */
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3234 float rho;
3235 PLIGHTINFOEL *object = NULL;
3236 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3237 struct list *e;
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3242 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3243 * the gl driver.
3245 if(!pLight) {
3246 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3247 return WINED3DERR_INVALIDCALL;
3250 switch(pLight->Type) {
3251 case WINED3DLIGHT_POINT:
3252 case WINED3DLIGHT_SPOT:
3253 case WINED3DLIGHT_PARALLELPOINT:
3254 case WINED3DLIGHT_GLSPOT:
3255 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3256 * most wanted
3258 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3259 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3260 return WINED3DERR_INVALIDCALL;
3262 break;
3264 case WINED3DLIGHT_DIRECTIONAL:
3265 /* Ignores attenuation */
3266 break;
3268 default:
3269 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3270 return WINED3DERR_INVALIDCALL;
3273 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3274 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3275 if(object->OriginalIndex == Index) break;
3276 object = NULL;
3279 if(!object) {
3280 TRACE("Adding new light\n");
3281 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3282 if(!object) {
3283 ERR("Out of memory error when allocating a light\n");
3284 return E_OUTOFMEMORY;
3286 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3287 object->glIndex = -1;
3288 object->OriginalIndex = Index;
3289 object->changed = TRUE;
3292 /* Initialize the object */
3293 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,
3294 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3295 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3296 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3297 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3298 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3299 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3301 /* Save away the information */
3302 object->OriginalParms = *pLight;
3304 switch (pLight->Type) {
3305 case WINED3DLIGHT_POINT:
3306 /* Position */
3307 object->lightPosn[0] = pLight->Position.x;
3308 object->lightPosn[1] = pLight->Position.y;
3309 object->lightPosn[2] = pLight->Position.z;
3310 object->lightPosn[3] = 1.0f;
3311 object->cutoff = 180.0f;
3312 /* FIXME: Range */
3313 break;
3315 case WINED3DLIGHT_DIRECTIONAL:
3316 /* Direction */
3317 object->lightPosn[0] = -pLight->Direction.x;
3318 object->lightPosn[1] = -pLight->Direction.y;
3319 object->lightPosn[2] = -pLight->Direction.z;
3320 object->lightPosn[3] = 0.0;
3321 object->exponent = 0.0f;
3322 object->cutoff = 180.0f;
3323 break;
3325 case WINED3DLIGHT_SPOT:
3326 /* Position */
3327 object->lightPosn[0] = pLight->Position.x;
3328 object->lightPosn[1] = pLight->Position.y;
3329 object->lightPosn[2] = pLight->Position.z;
3330 object->lightPosn[3] = 1.0;
3332 /* Direction */
3333 object->lightDirn[0] = pLight->Direction.x;
3334 object->lightDirn[1] = pLight->Direction.y;
3335 object->lightDirn[2] = pLight->Direction.z;
3336 object->lightDirn[3] = 1.0;
3339 * opengl-ish and d3d-ish spot lights use too different models for the
3340 * light "intensity" as a function of the angle towards the main light direction,
3341 * so we only can approximate very roughly.
3342 * however spot lights are rather rarely used in games (if ever used at all).
3343 * furthermore if still used, probably nobody pays attention to such details.
3345 if (pLight->Falloff == 0) {
3346 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3347 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3348 * will always be 1.0 for both of them, and we don't have to care for the
3349 * rest of the rather complex calculation
3351 object->exponent = 0;
3352 } else {
3353 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3354 if (rho < 0.0001) rho = 0.0001f;
3355 object->exponent = -0.3/log(cos(rho/2));
3357 if (object->exponent > 128.0) {
3358 object->exponent = 128.0;
3360 object->cutoff = pLight->Phi*90/M_PI;
3362 /* FIXME: Range */
3363 break;
3365 default:
3366 FIXME("Unrecognized light type %d\n", pLight->Type);
3369 /* Update the live definitions if the light is currently assigned a glIndex */
3370 if (object->glIndex != -1 && !This->isRecordingState) {
3371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3373 return WINED3D_OK;
3376 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3377 PLIGHTINFOEL *lightInfo = NULL;
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3380 struct list *e;
3381 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3383 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3384 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3385 if(lightInfo->OriginalIndex == Index) break;
3386 lightInfo = NULL;
3389 if (lightInfo == NULL) {
3390 TRACE("Light information requested but light not defined\n");
3391 return WINED3DERR_INVALIDCALL;
3394 *pLight = lightInfo->OriginalParms;
3395 return WINED3D_OK;
3398 /*****
3399 * Get / Set Light Enable
3400 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3401 *****/
3402 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3403 PLIGHTINFOEL *lightInfo = NULL;
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3406 struct list *e;
3407 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3409 /* Tests show true = 128...not clear why */
3410 Enable = Enable? 128: 0;
3412 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3413 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3414 if(lightInfo->OriginalIndex == Index) break;
3415 lightInfo = NULL;
3417 TRACE("Found light: %p\n", lightInfo);
3419 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3420 if (lightInfo == NULL) {
3422 TRACE("Light enabled requested but light not defined, so defining one!\n");
3423 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3425 /* Search for it again! Should be fairly quick as near head of list */
3426 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3427 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3428 if(lightInfo->OriginalIndex == Index) break;
3429 lightInfo = NULL;
3431 if (lightInfo == NULL) {
3432 FIXME("Adding default lights has failed dismally\n");
3433 return WINED3DERR_INVALIDCALL;
3437 lightInfo->enabledChanged = TRUE;
3438 if(!Enable) {
3439 if(lightInfo->glIndex != -1) {
3440 if(!This->isRecordingState) {
3441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3444 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3445 lightInfo->glIndex = -1;
3446 } else {
3447 TRACE("Light already disabled, nothing to do\n");
3449 lightInfo->enabled = FALSE;
3450 } else {
3451 lightInfo->enabled = TRUE;
3452 if (lightInfo->glIndex != -1) {
3453 /* nop */
3454 TRACE("Nothing to do as light was enabled\n");
3455 } else {
3456 int i;
3457 /* Find a free gl light */
3458 for(i = 0; i < This->maxConcurrentLights; i++) {
3459 if(This->updateStateBlock->activeLights[i] == NULL) {
3460 This->updateStateBlock->activeLights[i] = lightInfo;
3461 lightInfo->glIndex = i;
3462 break;
3465 if(lightInfo->glIndex == -1) {
3466 /* Our tests show that Windows returns D3D_OK in this situation, even with
3467 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3468 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3469 * as well for those lights.
3471 * TODO: Test how this affects rendering
3473 WARN("Too many concurrently active lights\n");
3474 return WINED3D_OK;
3477 /* i == lightInfo->glIndex */
3478 if(!This->isRecordingState) {
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3484 return WINED3D_OK;
3487 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3489 PLIGHTINFOEL *lightInfo = NULL;
3490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3491 struct list *e;
3492 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3493 TRACE("(%p) : for idx(%d)\n", This, Index);
3495 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3496 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3497 if(lightInfo->OriginalIndex == Index) break;
3498 lightInfo = NULL;
3501 if (lightInfo == NULL) {
3502 TRACE("Light enabled state requested but light not defined\n");
3503 return WINED3DERR_INVALIDCALL;
3505 /* true is 128 according to SetLightEnable */
3506 *pEnable = lightInfo->enabled ? 128 : 0;
3507 return WINED3D_OK;
3510 /*****
3511 * Get / Set Clip Planes
3512 *****/
3513 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3515 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3517 /* Validate Index */
3518 if (Index >= GL_LIMITS(clipplanes)) {
3519 TRACE("Application has requested clipplane this device doesn't support\n");
3520 return WINED3DERR_INVALIDCALL;
3523 This->updateStateBlock->changed.clipplane |= 1 << Index;
3525 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3526 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3527 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3528 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3529 TRACE("Application is setting old values over, nothing to do\n");
3530 return WINED3D_OK;
3533 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3534 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3535 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3536 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3538 /* Handle recording of state blocks */
3539 if (This->isRecordingState) {
3540 TRACE("Recording... not performing anything\n");
3541 return WINED3D_OK;
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3546 return WINED3D_OK;
3549 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3551 TRACE("(%p) : for idx %d\n", This, Index);
3553 /* Validate Index */
3554 if (Index >= GL_LIMITS(clipplanes)) {
3555 TRACE("Application has requested clipplane this device doesn't support\n");
3556 return WINED3DERR_INVALIDCALL;
3559 pPlane[0] = This->stateBlock->clipplane[Index][0];
3560 pPlane[1] = This->stateBlock->clipplane[Index][1];
3561 pPlane[2] = This->stateBlock->clipplane[Index][2];
3562 pPlane[3] = This->stateBlock->clipplane[Index][3];
3563 return WINED3D_OK;
3566 /*****
3567 * Get / Set Clip Plane Status
3568 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3569 *****/
3570 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3572 FIXME("(%p) : stub\n", This);
3573 if (NULL == pClipStatus) {
3574 return WINED3DERR_INVALIDCALL;
3576 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3577 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3578 return WINED3D_OK;
3581 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 FIXME("(%p) : stub\n", This);
3584 if (NULL == pClipStatus) {
3585 return WINED3DERR_INVALIDCALL;
3587 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3588 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3589 return WINED3D_OK;
3592 /*****
3593 * Get / Set Material
3594 *****/
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3598 This->updateStateBlock->changed.material = TRUE;
3599 This->updateStateBlock->material = *pMaterial;
3601 /* Handle recording of state blocks */
3602 if (This->isRecordingState) {
3603 TRACE("Recording... not performing anything\n");
3604 return WINED3D_OK;
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3608 return WINED3D_OK;
3611 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 *pMaterial = This->updateStateBlock->material;
3614 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3615 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3616 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3617 pMaterial->Ambient.b, pMaterial->Ambient.a);
3618 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3619 pMaterial->Specular.b, pMaterial->Specular.a);
3620 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3621 pMaterial->Emissive.b, pMaterial->Emissive.a);
3622 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3624 return WINED3D_OK;
3627 /*****
3628 * Get / Set Indices
3629 *****/
3630 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 IWineD3DBuffer *oldIdxs;
3634 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3635 oldIdxs = This->updateStateBlock->pIndexData;
3637 This->updateStateBlock->changed.indices = TRUE;
3638 This->updateStateBlock->pIndexData = pIndexData;
3639 This->updateStateBlock->IndexFmt = fmt;
3641 /* Handle recording of state blocks */
3642 if (This->isRecordingState) {
3643 TRACE("Recording... not performing anything\n");
3644 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3645 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3646 return WINED3D_OK;
3649 if(oldIdxs != pIndexData) {
3650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3651 if(pIndexData) {
3652 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3653 IWineD3DBuffer_AddRef(pIndexData);
3655 if(oldIdxs) {
3656 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3657 IWineD3DBuffer_Release(oldIdxs);
3661 return WINED3D_OK;
3664 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3667 *ppIndexData = This->stateBlock->pIndexData;
3669 /* up ref count on ppindexdata */
3670 if (*ppIndexData) {
3671 IWineD3DBuffer_AddRef(*ppIndexData);
3672 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3673 }else{
3674 TRACE("(%p) No index data set\n", This);
3676 TRACE("Returning %p\n", *ppIndexData);
3678 return WINED3D_OK;
3681 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3682 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3684 TRACE("(%p)->(%d)\n", This, BaseIndex);
3686 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3687 TRACE("Application is setting the old value over, nothing to do\n");
3688 return WINED3D_OK;
3691 This->updateStateBlock->baseVertexIndex = BaseIndex;
3693 if (This->isRecordingState) {
3694 TRACE("Recording... not performing anything\n");
3695 return WINED3D_OK;
3697 /* The base vertex index affects the stream sources */
3698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3699 return WINED3D_OK;
3702 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 TRACE("(%p) : base_index %p\n", This, base_index);
3706 *base_index = This->stateBlock->baseVertexIndex;
3708 TRACE("Returning %u\n", *base_index);
3710 return WINED3D_OK;
3713 /*****
3714 * Get / Set Viewports
3715 *****/
3716 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 TRACE("(%p)\n", This);
3720 This->updateStateBlock->changed.viewport = TRUE;
3721 This->updateStateBlock->viewport = *pViewport;
3723 /* Handle recording of state blocks */
3724 if (This->isRecordingState) {
3725 TRACE("Recording... not performing anything\n");
3726 return WINED3D_OK;
3729 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3730 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3733 return WINED3D_OK;
3737 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3739 TRACE("(%p)\n", This);
3740 *pViewport = This->stateBlock->viewport;
3741 return WINED3D_OK;
3744 /*****
3745 * Get / Set Render States
3746 * TODO: Verify against dx9 definitions
3747 *****/
3748 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 DWORD oldValue = This->stateBlock->renderState[State];
3753 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3755 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3756 This->updateStateBlock->renderState[State] = Value;
3758 /* Handle recording of state blocks */
3759 if (This->isRecordingState) {
3760 TRACE("Recording... not performing anything\n");
3761 return WINED3D_OK;
3764 /* Compared here and not before the assignment to allow proper stateblock recording */
3765 if(Value == oldValue) {
3766 TRACE("Application is setting the old value over, nothing to do\n");
3767 } else {
3768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3771 return WINED3D_OK;
3774 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3776 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3777 *pValue = This->stateBlock->renderState[State];
3778 return WINED3D_OK;
3781 /*****
3782 * Get / Set Sampler States
3783 * TODO: Verify against dx9 definitions
3784 *****/
3786 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 DWORD oldValue;
3790 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3791 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3793 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3794 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3797 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3798 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3799 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3802 * SetSampler is designed to allow for more than the standard up to 8 textures
3803 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3804 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3806 * http://developer.nvidia.com/object/General_FAQ.html#t6
3808 * There are two new settings for GForce
3809 * the sampler one:
3810 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3811 * and the texture one:
3812 * GL_MAX_TEXTURE_COORDS_ARB.
3813 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3814 ******************/
3816 oldValue = This->stateBlock->samplerState[Sampler][Type];
3817 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3818 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3820 /* Handle recording of state blocks */
3821 if (This->isRecordingState) {
3822 TRACE("Recording... not performing anything\n");
3823 return WINED3D_OK;
3826 if(oldValue == Value) {
3827 TRACE("Application is setting the old value over, nothing to do\n");
3828 return WINED3D_OK;
3831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3833 return WINED3D_OK;
3836 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3839 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3840 This, Sampler, debug_d3dsamplerstate(Type), Type);
3842 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3843 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3846 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3847 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3848 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3850 *Value = This->stateBlock->samplerState[Sampler][Type];
3851 TRACE("(%p) : Returning %#x\n", This, *Value);
3853 return WINED3D_OK;
3856 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3859 This->updateStateBlock->changed.scissorRect = TRUE;
3860 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3861 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3862 return WINED3D_OK;
3864 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3866 if(This->isRecordingState) {
3867 TRACE("Recording... not performing anything\n");
3868 return WINED3D_OK;
3871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3873 return WINED3D_OK;
3876 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3879 *pRect = This->updateStateBlock->scissorRect;
3880 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3881 return WINED3D_OK;
3884 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3886 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3888 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3890 This->updateStateBlock->vertexDecl = pDecl;
3891 This->updateStateBlock->changed.vertexDecl = TRUE;
3893 if (This->isRecordingState) {
3894 TRACE("Recording... not performing anything\n");
3895 return WINED3D_OK;
3896 } else if(pDecl == oldDecl) {
3897 /* Checked after the assignment to allow proper stateblock recording */
3898 TRACE("Application is setting the old declaration over, nothing to do\n");
3899 return WINED3D_OK;
3902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3903 return WINED3D_OK;
3906 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3911 *ppDecl = This->stateBlock->vertexDecl;
3912 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3913 return WINED3D_OK;
3916 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3918 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3920 This->updateStateBlock->vertexShader = pShader;
3921 This->updateStateBlock->changed.vertexShader = TRUE;
3923 if (This->isRecordingState) {
3924 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3925 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3926 TRACE("Recording... not performing anything\n");
3927 return WINED3D_OK;
3928 } else if(oldShader == pShader) {
3929 /* Checked here to allow proper stateblock recording */
3930 TRACE("App is setting the old shader over, nothing to do\n");
3931 return WINED3D_OK;
3934 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3935 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3936 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3940 return WINED3D_OK;
3943 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3946 if (NULL == ppShader) {
3947 return WINED3DERR_INVALIDCALL;
3949 *ppShader = This->stateBlock->vertexShader;
3950 if( NULL != *ppShader)
3951 IWineD3DVertexShader_AddRef(*ppShader);
3953 TRACE("(%p) : returning %p\n", This, *ppShader);
3954 return WINED3D_OK;
3957 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3958 IWineD3DDevice *iface,
3959 UINT start,
3960 CONST BOOL *srcData,
3961 UINT count) {
3963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3964 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3966 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3967 iface, srcData, start, count);
3969 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3971 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3972 for (i = 0; i < cnt; i++)
3973 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3975 for (i = start; i < cnt + start; ++i) {
3976 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3979 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3981 return WINED3D_OK;
3984 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3985 IWineD3DDevice *iface,
3986 UINT start,
3987 BOOL *dstData,
3988 UINT count) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 int cnt = min(count, MAX_CONST_B - start);
3993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3994 iface, dstData, start, count);
3996 if (dstData == NULL || cnt < 0)
3997 return WINED3DERR_INVALIDCALL;
3999 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4004 IWineD3DDevice *iface,
4005 UINT start,
4006 CONST int *srcData,
4007 UINT count) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4012 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4013 iface, srcData, start, count);
4015 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4017 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4018 for (i = 0; i < cnt; i++)
4019 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4020 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4022 for (i = start; i < cnt + start; ++i) {
4023 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4026 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4028 return WINED3D_OK;
4031 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4032 IWineD3DDevice *iface,
4033 UINT start,
4034 int *dstData,
4035 UINT count) {
4037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4038 int cnt = min(count, MAX_CONST_I - start);
4040 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4041 iface, dstData, start, count);
4043 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4044 return WINED3DERR_INVALIDCALL;
4046 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4047 return WINED3D_OK;
4050 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4051 IWineD3DDevice *iface,
4052 UINT start,
4053 CONST float *srcData,
4054 UINT count) {
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 UINT i;
4059 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4060 iface, srcData, start, count);
4062 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4063 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
4064 return WINED3DERR_INVALIDCALL;
4066 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4067 if(TRACE_ON(d3d)) {
4068 for (i = 0; i < count; i++)
4069 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4070 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4073 if (!This->isRecordingState)
4075 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4079 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4080 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4082 return WINED3D_OK;
4085 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4086 IWineD3DDevice *iface,
4087 UINT start,
4088 float *dstData,
4089 UINT count) {
4091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4092 int cnt = min(count, This->d3d_vshader_constantF - start);
4094 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4095 iface, dstData, start, count);
4097 if (dstData == NULL || cnt < 0)
4098 return WINED3DERR_INVALIDCALL;
4100 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4101 return WINED3D_OK;
4104 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4105 DWORD i;
4106 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4112 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4113 int i = This->rev_tex_unit_map[unit];
4114 int j = This->texUnitMap[stage];
4116 This->texUnitMap[stage] = unit;
4117 if (i != -1 && i != stage) {
4118 This->texUnitMap[i] = -1;
4121 This->rev_tex_unit_map[unit] = stage;
4122 if (j != -1 && j != unit) {
4123 This->rev_tex_unit_map[j] = -1;
4127 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4128 int i;
4130 This->fixed_function_usage_map = 0;
4131 for (i = 0; i < MAX_TEXTURES; ++i) {
4132 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4133 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4134 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4135 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4136 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4137 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4138 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4139 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4141 if (color_op == WINED3DTOP_DISABLE) {
4142 /* Not used, and disable higher stages */
4143 break;
4146 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4147 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4148 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4149 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4150 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4151 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4152 This->fixed_function_usage_map |= (1 << i);
4155 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4156 This->fixed_function_usage_map |= (1 << (i + 1));
4161 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4162 unsigned int i, tex;
4163 WORD ffu_map;
4165 device_update_fixed_function_usage_map(This);
4166 ffu_map = This->fixed_function_usage_map;
4168 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4169 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4170 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4172 if (!(ffu_map & 1)) continue;
4174 if (This->texUnitMap[i] != i) {
4175 device_map_stage(This, i, i);
4176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4177 markTextureStagesDirty(This, i);
4180 return;
4183 /* Now work out the mapping */
4184 tex = 0;
4185 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4187 if (!(ffu_map & 1)) continue;
4189 if (This->texUnitMap[i] != tex) {
4190 device_map_stage(This, i, tex);
4191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4192 markTextureStagesDirty(This, i);
4195 ++tex;
4199 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4200 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
4201 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
4202 unsigned int i;
4204 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4205 if (sampler_type[i] && This->texUnitMap[i] != i)
4207 device_map_stage(This, i, i);
4208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4209 if (i < MAX_TEXTURES) {
4210 markTextureStagesDirty(This, i);
4216 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4217 const DWORD *vshader_sampler_tokens, int unit)
4219 int current_mapping = This->rev_tex_unit_map[unit];
4221 if (current_mapping == -1) {
4222 /* Not currently used */
4223 return TRUE;
4226 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4227 /* Used by a fragment sampler */
4229 if (!pshader_sampler_tokens) {
4230 /* No pixel shader, check fixed function */
4231 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4234 /* Pixel shader, check the shader's sampler map */
4235 return !pshader_sampler_tokens[current_mapping];
4238 /* Used by a vertex sampler */
4239 return !vshader_sampler_tokens[current_mapping];
4242 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4243 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
4244 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
4245 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
4246 int start = GL_LIMITS(combined_samplers) - 1;
4247 int i;
4249 if (ps) {
4250 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4252 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4253 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4254 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4257 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4258 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4259 if (vshader_sampler_type[i])
4261 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4263 /* Already mapped somewhere */
4264 continue;
4267 while (start >= 0) {
4268 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4270 device_map_stage(This, vsampler_idx, start);
4271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4273 --start;
4274 break;
4277 --start;
4283 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4284 BOOL vs = use_vs(This->stateBlock);
4285 BOOL ps = use_ps(This->stateBlock);
4287 * Rules are:
4288 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4289 * that would be really messy and require shader recompilation
4290 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4291 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4293 if (ps) {
4294 device_map_psamplers(This);
4295 } else {
4296 device_map_fixed_function_samplers(This);
4299 if (vs) {
4300 device_map_vsamplers(This, ps);
4304 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4306 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4307 This->updateStateBlock->pixelShader = pShader;
4308 This->updateStateBlock->changed.pixelShader = TRUE;
4310 /* Handle recording of state blocks */
4311 if (This->isRecordingState) {
4312 TRACE("Recording... not performing anything\n");
4315 if (This->isRecordingState) {
4316 TRACE("Recording... not performing anything\n");
4317 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4318 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4319 return WINED3D_OK;
4322 if(pShader == oldShader) {
4323 TRACE("App is setting the old pixel shader over, nothing to do\n");
4324 return WINED3D_OK;
4327 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4328 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4330 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4333 return WINED3D_OK;
4336 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 if (NULL == ppShader) {
4340 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4341 return WINED3DERR_INVALIDCALL;
4344 *ppShader = This->stateBlock->pixelShader;
4345 if (NULL != *ppShader) {
4346 IWineD3DPixelShader_AddRef(*ppShader);
4348 TRACE("(%p) : returning %p\n", This, *ppShader);
4349 return WINED3D_OK;
4352 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4353 IWineD3DDevice *iface,
4354 UINT start,
4355 CONST BOOL *srcData,
4356 UINT count) {
4358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4359 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4361 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4362 iface, srcData, start, count);
4364 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4366 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4367 for (i = 0; i < cnt; i++)
4368 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4370 for (i = start; i < cnt + start; ++i) {
4371 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4374 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4376 return WINED3D_OK;
4379 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4380 IWineD3DDevice *iface,
4381 UINT start,
4382 BOOL *dstData,
4383 UINT count) {
4385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4386 int cnt = min(count, MAX_CONST_B - start);
4388 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4389 iface, dstData, start, count);
4391 if (dstData == NULL || cnt < 0)
4392 return WINED3DERR_INVALIDCALL;
4394 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4395 return WINED3D_OK;
4398 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4399 IWineD3DDevice *iface,
4400 UINT start,
4401 CONST int *srcData,
4402 UINT count) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4407 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4408 iface, srcData, start, count);
4410 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4412 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4413 for (i = 0; i < cnt; i++)
4414 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4415 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4417 for (i = start; i < cnt + start; ++i) {
4418 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4421 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4423 return WINED3D_OK;
4426 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4427 IWineD3DDevice *iface,
4428 UINT start,
4429 int *dstData,
4430 UINT count) {
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4433 int cnt = min(count, MAX_CONST_I - start);
4435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4436 iface, dstData, start, count);
4438 if (dstData == NULL || cnt < 0)
4439 return WINED3DERR_INVALIDCALL;
4441 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4442 return WINED3D_OK;
4445 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4446 IWineD3DDevice *iface,
4447 UINT start,
4448 CONST float *srcData,
4449 UINT count) {
4451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 UINT i;
4454 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4455 iface, srcData, start, count);
4457 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4458 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4459 return WINED3DERR_INVALIDCALL;
4461 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4462 if(TRACE_ON(d3d)) {
4463 for (i = 0; i < count; i++)
4464 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4465 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4468 if (!This->isRecordingState)
4470 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4474 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4475 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4477 return WINED3D_OK;
4480 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4481 IWineD3DDevice *iface,
4482 UINT start,
4483 float *dstData,
4484 UINT count) {
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 int cnt = min(count, This->d3d_pshader_constantF - start);
4489 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4490 iface, dstData, start, count);
4492 if (dstData == NULL || cnt < 0)
4493 return WINED3DERR_INVALIDCALL;
4495 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4496 return WINED3D_OK;
4499 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4500 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4501 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4502 DWORD DestFVF)
4504 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4505 unsigned int i;
4506 WINED3DVIEWPORT vp;
4507 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4508 BOOL doClip;
4509 DWORD numTextures;
4511 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4513 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4516 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4518 ERR("Source has no position mask\n");
4519 return WINED3DERR_INVALIDCALL;
4522 /* We might access VBOs from this code, so hold the lock */
4523 ENTER_GL();
4525 if (dest->resource.allocatedMemory == NULL) {
4526 buffer_get_sysmem(dest);
4529 /* Get a pointer into the destination vbo(create one if none exists) and
4530 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4532 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4534 dest->flags |= WINED3D_BUFFER_CREATEBO;
4535 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4538 if (dest->buffer_object)
4540 unsigned char extrabytes = 0;
4541 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4542 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4543 * this may write 4 extra bytes beyond the area that should be written
4545 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4546 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4547 if(!dest_conv_addr) {
4548 ERR("Out of memory\n");
4549 /* Continue without storing converted vertices */
4551 dest_conv = dest_conv_addr;
4554 /* Should I clip?
4555 * a) WINED3DRS_CLIPPING is enabled
4556 * b) WINED3DVOP_CLIP is passed
4558 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4559 static BOOL warned = FALSE;
4561 * The clipping code is not quite correct. Some things need
4562 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4563 * so disable clipping for now.
4564 * (The graphics in Half-Life are broken, and my processvertices
4565 * test crashes with IDirect3DDevice3)
4566 doClip = TRUE;
4568 doClip = FALSE;
4569 if(!warned) {
4570 warned = TRUE;
4571 FIXME("Clipping is broken and disabled for now\n");
4573 } else doClip = FALSE;
4574 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4576 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4577 WINED3DTS_VIEW,
4578 &view_mat);
4579 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4580 WINED3DTS_PROJECTION,
4581 &proj_mat);
4582 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4583 WINED3DTS_WORLDMATRIX(0),
4584 &world_mat);
4586 TRACE("View mat:\n");
4587 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);
4588 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);
4589 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);
4590 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);
4592 TRACE("Proj mat:\n");
4593 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);
4594 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);
4595 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);
4596 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);
4598 TRACE("World mat:\n");
4599 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);
4600 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);
4601 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);
4602 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);
4604 /* Get the viewport */
4605 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4606 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4607 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4609 multiply_matrix(&mat,&view_mat,&world_mat);
4610 multiply_matrix(&mat,&proj_mat,&mat);
4612 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4614 for (i = 0; i < dwCount; i+= 1) {
4615 unsigned int tex_index;
4617 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4618 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4619 /* The position first */
4620 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4621 const float *p = (const float *)(element->data + i * element->stride);
4622 float x, y, z, rhw;
4623 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4625 /* Multiplication with world, view and projection matrix */
4626 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);
4627 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);
4628 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);
4629 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);
4631 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4633 /* WARNING: The following things are taken from d3d7 and were not yet checked
4634 * against d3d8 or d3d9!
4637 /* Clipping conditions: From msdn
4639 * A vertex is clipped if it does not match the following requirements
4640 * -rhw < x <= rhw
4641 * -rhw < y <= rhw
4642 * 0 < z <= rhw
4643 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4645 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4646 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4650 if( !doClip ||
4651 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4652 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4653 ( rhw > eps ) ) ) {
4655 /* "Normal" viewport transformation (not clipped)
4656 * 1) The values are divided by rhw
4657 * 2) The y axis is negative, so multiply it with -1
4658 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4659 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4660 * 4) Multiply x with Width/2 and add Width/2
4661 * 5) The same for the height
4662 * 6) Add the viewpoint X and Y to the 2D coordinates and
4663 * The minimum Z value to z
4664 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4666 * Well, basically it's simply a linear transformation into viewport
4667 * coordinates
4670 x /= rhw;
4671 y /= rhw;
4672 z /= rhw;
4674 y *= -1;
4676 x *= vp.Width / 2;
4677 y *= vp.Height / 2;
4678 z *= vp.MaxZ - vp.MinZ;
4680 x += vp.Width / 2 + vp.X;
4681 y += vp.Height / 2 + vp.Y;
4682 z += vp.MinZ;
4684 rhw = 1 / rhw;
4685 } else {
4686 /* That vertex got clipped
4687 * Contrary to OpenGL it is not dropped completely, it just
4688 * undergoes a different calculation.
4690 TRACE("Vertex got clipped\n");
4691 x += rhw;
4692 y += rhw;
4694 x /= 2;
4695 y /= 2;
4697 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4698 * outside of the main vertex buffer memory. That needs some more
4699 * investigation...
4703 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4706 ( (float *) dest_ptr)[0] = x;
4707 ( (float *) dest_ptr)[1] = y;
4708 ( (float *) dest_ptr)[2] = z;
4709 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4711 dest_ptr += 3 * sizeof(float);
4713 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4714 dest_ptr += sizeof(float);
4717 if(dest_conv) {
4718 float w = 1 / rhw;
4719 ( (float *) dest_conv)[0] = x * w;
4720 ( (float *) dest_conv)[1] = y * w;
4721 ( (float *) dest_conv)[2] = z * w;
4722 ( (float *) dest_conv)[3] = w;
4724 dest_conv += 3 * sizeof(float);
4726 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4727 dest_conv += sizeof(float);
4731 if (DestFVF & WINED3DFVF_PSIZE) {
4732 dest_ptr += sizeof(DWORD);
4733 if(dest_conv) dest_conv += sizeof(DWORD);
4735 if (DestFVF & WINED3DFVF_NORMAL) {
4736 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4737 const float *normal = (const float *)(element->data + i * element->stride);
4738 /* AFAIK this should go into the lighting information */
4739 FIXME("Didn't expect the destination to have a normal\n");
4740 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4741 if(dest_conv) {
4742 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4746 if (DestFVF & WINED3DFVF_DIFFUSE) {
4747 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4748 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4749 if(!color_d) {
4750 static BOOL warned = FALSE;
4752 if(!warned) {
4753 ERR("No diffuse color in source, but destination has one\n");
4754 warned = TRUE;
4757 *( (DWORD *) dest_ptr) = 0xffffffff;
4758 dest_ptr += sizeof(DWORD);
4760 if(dest_conv) {
4761 *( (DWORD *) dest_conv) = 0xffffffff;
4762 dest_conv += sizeof(DWORD);
4765 else {
4766 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4767 if(dest_conv) {
4768 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4769 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4770 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4771 dest_conv += sizeof(DWORD);
4776 if (DestFVF & WINED3DFVF_SPECULAR) {
4777 /* What's the color value in the feedback buffer? */
4778 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4779 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4780 if(!color_s) {
4781 static BOOL warned = FALSE;
4783 if(!warned) {
4784 ERR("No specular color in source, but destination has one\n");
4785 warned = TRUE;
4788 *( (DWORD *) dest_ptr) = 0xFF000000;
4789 dest_ptr += sizeof(DWORD);
4791 if(dest_conv) {
4792 *( (DWORD *) dest_conv) = 0xFF000000;
4793 dest_conv += sizeof(DWORD);
4796 else {
4797 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4798 if(dest_conv) {
4799 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4800 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4801 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4802 dest_conv += sizeof(DWORD);
4807 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4808 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4809 const float *tex_coord = (const float *)(element->data + i * element->stride);
4810 if(!tex_coord) {
4811 ERR("No source texture, but destination requests one\n");
4812 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4813 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4815 else {
4816 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4817 if(dest_conv) {
4818 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4824 if(dest_conv) {
4825 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4826 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4827 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4828 dwCount * get_flexible_vertex_size(DestFVF),
4829 dest_conv_addr));
4830 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4831 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4834 LEAVE_GL();
4836 return WINED3D_OK;
4838 #undef copy_and_next
4840 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4841 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4842 DWORD DestFVF)
4844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4845 struct wined3d_stream_info stream_info;
4846 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4847 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4849 if(pVertexDecl) {
4850 ERR("Output vertex declaration not implemented yet\n");
4853 /* Need any context to write to the vbo. */
4854 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4856 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4857 * control the streamIsUP flag, thus restore it afterwards.
4859 This->stateBlock->streamIsUP = FALSE;
4860 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4861 This->stateBlock->streamIsUP = streamWasUP;
4863 if(vbo || SrcStartIndex) {
4864 unsigned int i;
4865 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4866 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4868 * Also get the start index in, but only loop over all elements if there's something to add at all.
4870 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4872 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4873 if (e->buffer_object)
4875 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4876 e->buffer_object = 0;
4877 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4878 ENTER_GL();
4879 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4880 vb->buffer_object = 0;
4881 LEAVE_GL();
4883 if (e->data) e->data += e->stride * SrcStartIndex;
4887 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4888 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4891 /*****
4892 * Get / Set Texture Stage States
4893 * TODO: Verify against dx9 definitions
4894 *****/
4895 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4899 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4901 if (Stage >= MAX_TEXTURES) {
4902 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4903 return WINED3D_OK;
4906 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4907 This->updateStateBlock->textureState[Stage][Type] = Value;
4909 if (This->isRecordingState) {
4910 TRACE("Recording... not performing anything\n");
4911 return WINED3D_OK;
4914 /* Checked after the assignments to allow proper stateblock recording */
4915 if(oldValue == Value) {
4916 TRACE("App is setting the old value over, nothing to do\n");
4917 return WINED3D_OK;
4920 if(Stage > This->stateBlock->lowest_disabled_stage &&
4921 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4922 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4923 * Changes in other states are important on disabled stages too
4925 return WINED3D_OK;
4928 if(Type == WINED3DTSS_COLOROP) {
4929 unsigned int i;
4931 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4932 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4933 * they have to be disabled
4935 * The current stage is dirtified below.
4937 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4938 TRACE("Additionally dirtifying stage %u\n", i);
4939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4941 This->stateBlock->lowest_disabled_stage = Stage;
4942 TRACE("New lowest disabled: %u\n", Stage);
4943 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4944 /* Previously disabled stage enabled. Stages above it may need enabling
4945 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4946 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4948 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4951 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4952 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4953 break;
4955 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4958 This->stateBlock->lowest_disabled_stage = i;
4959 TRACE("New lowest disabled: %u\n", i);
4963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4965 return WINED3D_OK;
4968 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4971 *pValue = This->updateStateBlock->textureState[Stage][Type];
4972 return WINED3D_OK;
4975 /*****
4976 * Get / Set Texture
4977 *****/
4978 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 IWineD3DBaseTexture *oldTexture;
4982 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4984 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4985 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4988 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4989 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4990 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4993 oldTexture = This->updateStateBlock->textures[Stage];
4995 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4996 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4998 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4999 return WINED3DERR_INVALIDCALL;
5002 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5003 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5005 This->updateStateBlock->changed.textures |= 1 << Stage;
5006 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5007 This->updateStateBlock->textures[Stage] = pTexture;
5009 /* Handle recording of state blocks */
5010 if (This->isRecordingState) {
5011 TRACE("Recording... not performing anything\n");
5012 return WINED3D_OK;
5015 if(oldTexture == pTexture) {
5016 TRACE("App is setting the same texture again, nothing to do\n");
5017 return WINED3D_OK;
5020 /** NOTE: MSDN says that setTexture increases the reference count,
5021 * and that the application must set the texture back to null (or have a leaky application),
5022 * This means we should pass the refcount up to the parent
5023 *******************************/
5024 if (NULL != This->updateStateBlock->textures[Stage]) {
5025 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5026 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5027 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5029 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5031 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5036 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5037 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5038 * so the COLOROP and ALPHAOP have to be dirtified.
5040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5043 if(bindCount == 1) {
5044 new->baseTexture.sampler = Stage;
5046 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5050 if (NULL != oldTexture) {
5051 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5052 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5054 IWineD3DBaseTexture_Release(oldTexture);
5055 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5060 if(bindCount && old->baseTexture.sampler == Stage) {
5061 int i;
5062 /* Have to do a search for the other sampler(s) where the texture is bound to
5063 * Shouldn't happen as long as apps bind a texture only to one stage
5065 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5066 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5067 if(This->updateStateBlock->textures[i] == oldTexture) {
5068 old->baseTexture.sampler = i;
5069 break;
5075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5077 return WINED3D_OK;
5080 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5085 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5086 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5089 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5090 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5091 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5094 *ppTexture=This->stateBlock->textures[Stage];
5095 if (*ppTexture)
5096 IWineD3DBaseTexture_AddRef(*ppTexture);
5098 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5100 return WINED3D_OK;
5103 /*****
5104 * Get Back Buffer
5105 *****/
5106 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5107 IWineD3DSurface **ppBackBuffer) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 IWineD3DSwapChain *swapChain;
5110 HRESULT hr;
5112 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5114 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5115 if (hr == WINED3D_OK) {
5116 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5117 IWineD3DSwapChain_Release(swapChain);
5118 } else {
5119 *ppBackBuffer = NULL;
5121 return hr;
5124 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 WARN("(%p) : stub, calling idirect3d for now\n", This);
5127 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5130 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5132 IWineD3DSwapChain *swapChain;
5133 HRESULT hr;
5135 if(iSwapChain > 0) {
5136 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5137 if (hr == WINED3D_OK) {
5138 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5139 IWineD3DSwapChain_Release(swapChain);
5140 } else {
5141 FIXME("(%p) Error getting display mode\n", This);
5143 } else {
5144 /* Don't read the real display mode,
5145 but return the stored mode instead. X11 can't change the color
5146 depth, and some apps are pretty angry if they SetDisplayMode from
5147 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5149 Also don't relay to the swapchain because with ddraw it's possible
5150 that there isn't a swapchain at all */
5151 pMode->Width = This->ddraw_width;
5152 pMode->Height = This->ddraw_height;
5153 pMode->Format = This->ddraw_format;
5154 pMode->RefreshRate = 0;
5155 hr = WINED3D_OK;
5158 return hr;
5161 /*****
5162 * Stateblock related functions
5163 *****/
5165 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 IWineD3DStateBlock *stateblock;
5168 HRESULT hr;
5170 TRACE("(%p)\n", This);
5172 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5174 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5175 if (FAILED(hr)) return hr;
5177 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5178 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5179 This->isRecordingState = TRUE;
5181 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5183 return WINED3D_OK;
5186 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5188 unsigned int i, j;
5189 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5191 if (!This->isRecordingState) {
5192 WARN("(%p) not recording! returning error\n", This);
5193 *ppStateBlock = NULL;
5194 return WINED3DERR_INVALIDCALL;
5197 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5199 DWORD map = object->changed.renderState[i];
5200 for (j = 0; map; map >>= 1, ++j)
5202 if (!(map & 1)) continue;
5204 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5208 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5210 DWORD map = object->changed.transform[i];
5211 for (j = 0; map; map >>= 1, ++j)
5213 if (!(map & 1)) continue;
5215 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5218 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5219 if(object->changed.vertexShaderConstantsF[i]) {
5220 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5221 object->num_contained_vs_consts_f++;
5224 for(i = 0; i < MAX_CONST_I; i++) {
5225 if (object->changed.vertexShaderConstantsI & (1 << i))
5227 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5228 object->num_contained_vs_consts_i++;
5231 for(i = 0; i < MAX_CONST_B; i++) {
5232 if (object->changed.vertexShaderConstantsB & (1 << i))
5234 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5235 object->num_contained_vs_consts_b++;
5238 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5240 if (object->changed.pixelShaderConstantsF[i])
5242 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5243 ++object->num_contained_ps_consts_f;
5246 for(i = 0; i < MAX_CONST_I; i++) {
5247 if (object->changed.pixelShaderConstantsI & (1 << i))
5249 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5250 object->num_contained_ps_consts_i++;
5253 for(i = 0; i < MAX_CONST_B; i++) {
5254 if (object->changed.pixelShaderConstantsB & (1 << i))
5256 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5257 object->num_contained_ps_consts_b++;
5260 for(i = 0; i < MAX_TEXTURES; i++) {
5261 DWORD map = object->changed.textureState[i];
5263 for(j = 0; map; map >>= 1, ++j)
5265 if (!(map & 1)) continue;
5267 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5268 object->contained_tss_states[object->num_contained_tss_states].state = j;
5269 ++object->num_contained_tss_states;
5272 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5273 DWORD map = object->changed.samplerState[i];
5275 for (j = 0; map; map >>= 1, ++j)
5277 if (!(map & 1)) continue;
5279 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5280 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5281 ++object->num_contained_sampler_states;
5285 *ppStateBlock = (IWineD3DStateBlock*) object;
5286 This->isRecordingState = FALSE;
5287 This->updateStateBlock = This->stateBlock;
5288 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5289 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5290 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5291 return WINED3D_OK;
5294 /*****
5295 * Scene related functions
5296 *****/
5297 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5298 /* At the moment we have no need for any functionality at the beginning
5299 of a scene */
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5301 TRACE("(%p)\n", This);
5303 if(This->inScene) {
5304 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5305 return WINED3DERR_INVALIDCALL;
5307 This->inScene = TRUE;
5308 return WINED3D_OK;
5311 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5313 TRACE("(%p)\n", This);
5315 if(!This->inScene) {
5316 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5317 return WINED3DERR_INVALIDCALL;
5320 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5321 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5322 glFlush();
5323 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5324 * fails
5327 This->inScene = FALSE;
5328 return WINED3D_OK;
5331 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5332 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5333 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 IWineD3DSwapChain *swapChain = NULL;
5336 int i;
5337 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5339 TRACE("(%p) Presenting the frame\n", This);
5341 for(i = 0 ; i < swapchains ; i ++) {
5343 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5344 TRACE("presentinng chain %d, %p\n", i, swapChain);
5345 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5346 IWineD3DSwapChain_Release(swapChain);
5349 return WINED3D_OK;
5352 /* Not called from the VTable (internal subroutine) */
5353 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5354 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5355 float Z, DWORD Stencil) {
5356 GLbitfield glMask = 0;
5357 unsigned int i;
5358 WINED3DRECT curRect;
5359 RECT vp_rect;
5360 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5361 UINT drawable_width, drawable_height;
5362 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5363 IWineD3DSwapChainImpl *swapchain = NULL;
5365 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5366 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5367 * for the cleared parts, and the untouched parts.
5369 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5370 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5371 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5372 * checking all this if the dest surface is in the drawable anyway.
5374 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5375 while(1) {
5376 if(vp->X != 0 || vp->Y != 0 ||
5377 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5378 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5379 break;
5381 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5382 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5383 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5384 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5385 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5386 break;
5388 if(Count > 0 && pRects && (
5389 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5390 pRects[0].x2 < target->currentDesc.Width ||
5391 pRects[0].y2 < target->currentDesc.Height)) {
5392 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5393 break;
5395 break;
5399 target->get_drawable_size(target, &drawable_width, &drawable_height);
5401 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5402 ENTER_GL();
5404 /* Only set the values up once, as they are not changing */
5405 if (Flags & WINED3DCLEAR_STENCIL) {
5406 glClearStencil(Stencil);
5407 checkGLcall("glClearStencil");
5408 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5409 glStencilMask(0xFFFFFFFF);
5412 if (Flags & WINED3DCLEAR_ZBUFFER) {
5413 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5414 glDepthMask(GL_TRUE);
5415 glClearDepth(Z);
5416 checkGLcall("glClearDepth");
5417 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5420 if (vp->X != 0 || vp->Y != 0 ||
5421 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5422 surface_load_ds_location(This->stencilBufferTarget, location);
5424 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5425 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5426 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5427 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5428 surface_load_ds_location(This->stencilBufferTarget, location);
5430 else if (Count > 0 && pRects && (
5431 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5432 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5433 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5434 surface_load_ds_location(This->stencilBufferTarget, location);
5438 if (Flags & WINED3DCLEAR_TARGET) {
5439 TRACE("Clearing screen with glClear to color %x\n", Color);
5440 glClearColor(D3DCOLOR_R(Color),
5441 D3DCOLOR_G(Color),
5442 D3DCOLOR_B(Color),
5443 D3DCOLOR_A(Color));
5444 checkGLcall("glClearColor");
5446 /* Clear ALL colors! */
5447 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5448 glMask = glMask | GL_COLOR_BUFFER_BIT;
5451 vp_rect.left = vp->X;
5452 vp_rect.top = vp->Y;
5453 vp_rect.right = vp->X + vp->Width;
5454 vp_rect.bottom = vp->Y + vp->Height;
5455 if (!(Count > 0 && pRects)) {
5456 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5457 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5459 if(This->render_offscreen) {
5460 glScissor(vp_rect.left, vp_rect.top,
5461 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5462 } else {
5463 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5464 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5466 checkGLcall("glScissor");
5467 glClear(glMask);
5468 checkGLcall("glClear");
5469 } else {
5470 /* Now process each rect in turn */
5471 for (i = 0; i < Count; i++) {
5472 /* Note gl uses lower left, width/height */
5473 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5474 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5475 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5477 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5478 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5479 curRect.x1, (target->currentDesc.Height - curRect.y2),
5480 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5482 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5483 * The rectangle is not cleared, no error is returned, but further rectanlges are
5484 * still cleared if they are valid
5486 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5487 TRACE("Rectangle with negative dimensions, ignoring\n");
5488 continue;
5491 if(This->render_offscreen) {
5492 glScissor(curRect.x1, curRect.y1,
5493 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5494 } else {
5495 glScissor(curRect.x1, drawable_height - curRect.y2,
5496 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5498 checkGLcall("glScissor");
5500 glClear(glMask);
5501 checkGLcall("glClear");
5505 /* Restore the old values (why..?) */
5506 if (Flags & WINED3DCLEAR_STENCIL) {
5507 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5509 if (Flags & WINED3DCLEAR_TARGET) {
5510 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5511 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5512 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5513 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5514 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5516 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5517 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5519 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5521 if (Flags & WINED3DCLEAR_ZBUFFER) {
5522 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5523 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5524 surface_modify_ds_location(This->stencilBufferTarget, location);
5527 LEAVE_GL();
5529 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5530 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5531 glFlush();
5533 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5536 return WINED3D_OK;
5539 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5540 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5544 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5545 Count, pRects, Flags, Color, Z, Stencil);
5547 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5548 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5549 /* TODO: What about depth stencil buffers without stencil bits? */
5550 return WINED3DERR_INVALIDCALL;
5553 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5556 /*****
5557 * Drawing functions
5558 *****/
5560 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5561 WINED3DPRIMITIVETYPE primitive_type)
5563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5565 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5567 This->updateStateBlock->changed.primitive_type = TRUE;
5568 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5571 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5572 WINED3DPRIMITIVETYPE *primitive_type)
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5576 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5578 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5580 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5583 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5587 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5589 if(!This->stateBlock->vertexDecl) {
5590 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5591 return WINED3DERR_INVALIDCALL;
5594 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5595 if(This->stateBlock->streamIsUP) {
5596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5597 This->stateBlock->streamIsUP = FALSE;
5600 if(This->stateBlock->loadBaseVertexIndex != 0) {
5601 This->stateBlock->loadBaseVertexIndex = 0;
5602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5604 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5605 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5606 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5607 return WINED3D_OK;
5610 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5611 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 UINT idxStride = 2;
5615 IWineD3DBuffer *pIB;
5616 GLuint vbo;
5618 pIB = This->stateBlock->pIndexData;
5619 if (!pIB) {
5620 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5621 * without an index buffer set. (The first time at least...)
5622 * D3D8 simply dies, but I doubt it can do much harm to return
5623 * D3DERR_INVALIDCALL there as well. */
5624 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5625 return WINED3DERR_INVALIDCALL;
5628 if(!This->stateBlock->vertexDecl) {
5629 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5630 return WINED3DERR_INVALIDCALL;
5633 if(This->stateBlock->streamIsUP) {
5634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5635 This->stateBlock->streamIsUP = FALSE;
5637 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5639 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5640 This, minIndex, NumVertices, startIndex, index_count);
5642 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5643 idxStride = 2;
5644 } else {
5645 idxStride = 4;
5648 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5649 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5653 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5654 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5656 return WINED3D_OK;
5659 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5660 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5663 IWineD3DBuffer *vb;
5665 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5666 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5668 if(!This->stateBlock->vertexDecl) {
5669 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5670 return WINED3DERR_INVALIDCALL;
5673 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5674 vb = This->stateBlock->streamSource[0];
5675 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5676 if (vb) IWineD3DBuffer_Release(vb);
5677 This->stateBlock->streamOffset[0] = 0;
5678 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5679 This->stateBlock->streamIsUP = TRUE;
5680 This->stateBlock->loadBaseVertexIndex = 0;
5682 /* TODO: Only mark dirty if drawing from a different UP address */
5683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5685 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5686 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5688 /* MSDN specifies stream zero settings must be set to NULL */
5689 This->stateBlock->streamStride[0] = 0;
5690 This->stateBlock->streamSource[0] = NULL;
5692 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5693 * the new stream sources or use UP drawing again
5695 return WINED3D_OK;
5698 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5699 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5700 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5702 int idxStride;
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 IWineD3DBuffer *vb;
5705 IWineD3DBuffer *ib;
5707 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5708 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5709 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5711 if(!This->stateBlock->vertexDecl) {
5712 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5713 return WINED3DERR_INVALIDCALL;
5716 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5717 idxStride = 2;
5718 } else {
5719 idxStride = 4;
5722 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5723 vb = This->stateBlock->streamSource[0];
5724 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5725 if (vb) IWineD3DBuffer_Release(vb);
5726 This->stateBlock->streamIsUP = TRUE;
5727 This->stateBlock->streamOffset[0] = 0;
5728 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5730 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5731 This->stateBlock->baseVertexIndex = 0;
5732 This->stateBlock->loadBaseVertexIndex = 0;
5733 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5737 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5738 idxStride, pIndexData, MinVertexIndex);
5740 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5741 This->stateBlock->streamSource[0] = NULL;
5742 This->stateBlock->streamStride[0] = 0;
5743 ib = This->stateBlock->pIndexData;
5744 if(ib) {
5745 IWineD3DBuffer_Release(ib);
5746 This->stateBlock->pIndexData = NULL;
5748 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5749 * SetStreamSource to specify a vertex buffer
5752 return WINED3D_OK;
5755 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5756 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5760 /* Mark the state dirty until we have nicer tracking
5761 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5762 * that value.
5764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5766 This->stateBlock->baseVertexIndex = 0;
5767 This->up_strided = DrawPrimStrideData;
5768 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5769 This->up_strided = NULL;
5770 return WINED3D_OK;
5773 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5774 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5775 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5778 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5780 /* Mark the state dirty until we have nicer tracking
5781 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5782 * that value.
5784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5786 This->stateBlock->streamIsUP = TRUE;
5787 This->stateBlock->baseVertexIndex = 0;
5788 This->up_strided = DrawPrimStrideData;
5789 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5790 This->up_strided = NULL;
5791 return WINED3D_OK;
5794 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5795 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5796 * not callable by the app directly no parameter validation checks are needed here.
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5799 WINED3DLOCKED_BOX src;
5800 WINED3DLOCKED_BOX dst;
5801 HRESULT hr;
5802 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5804 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5805 * dirtification to improve loading performance.
5807 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5808 if(FAILED(hr)) return hr;
5809 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5810 if(FAILED(hr)) {
5811 IWineD3DVolume_UnlockBox(pSourceVolume);
5812 return hr;
5815 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5817 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5818 if(FAILED(hr)) {
5819 IWineD3DVolume_UnlockBox(pSourceVolume);
5820 } else {
5821 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5823 return hr;
5826 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5827 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5829 HRESULT hr = WINED3D_OK;
5830 WINED3DRESOURCETYPE sourceType;
5831 WINED3DRESOURCETYPE destinationType;
5832 int i ,levels;
5834 /* TODO: think about moving the code into IWineD3DBaseTexture */
5836 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5838 /* verify that the source and destination textures aren't NULL */
5839 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5840 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5841 This, pSourceTexture, pDestinationTexture);
5842 hr = WINED3DERR_INVALIDCALL;
5845 if (pSourceTexture == pDestinationTexture) {
5846 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5847 This, pSourceTexture, pDestinationTexture);
5848 hr = WINED3DERR_INVALIDCALL;
5850 /* Verify that the source and destination textures are the same type */
5851 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5852 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5854 if (sourceType != destinationType) {
5855 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5856 This);
5857 hr = WINED3DERR_INVALIDCALL;
5860 /* check that both textures have the identical numbers of levels */
5861 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5862 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5863 hr = WINED3DERR_INVALIDCALL;
5866 if (WINED3D_OK == hr) {
5867 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5869 /* Make sure that the destination texture is loaded */
5870 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5872 /* Update every surface level of the texture */
5873 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5875 switch (sourceType) {
5876 case WINED3DRTYPE_TEXTURE:
5878 IWineD3DSurface *srcSurface;
5879 IWineD3DSurface *destSurface;
5881 for (i = 0 ; i < levels ; ++i) {
5882 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5883 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5884 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5885 IWineD3DSurface_Release(srcSurface);
5886 IWineD3DSurface_Release(destSurface);
5887 if (WINED3D_OK != hr) {
5888 WARN("(%p) : Call to update surface failed\n", This);
5889 return hr;
5893 break;
5894 case WINED3DRTYPE_CUBETEXTURE:
5896 IWineD3DSurface *srcSurface;
5897 IWineD3DSurface *destSurface;
5898 WINED3DCUBEMAP_FACES faceType;
5900 for (i = 0 ; i < levels ; ++i) {
5901 /* Update each cube face */
5902 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5903 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5904 if (WINED3D_OK != hr) {
5905 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5906 } else {
5907 TRACE("Got srcSurface %p\n", srcSurface);
5909 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5910 if (WINED3D_OK != hr) {
5911 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5912 } else {
5913 TRACE("Got desrSurface %p\n", destSurface);
5915 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5916 IWineD3DSurface_Release(srcSurface);
5917 IWineD3DSurface_Release(destSurface);
5918 if (WINED3D_OK != hr) {
5919 WARN("(%p) : Call to update surface failed\n", This);
5920 return hr;
5925 break;
5927 case WINED3DRTYPE_VOLUMETEXTURE:
5929 IWineD3DVolume *srcVolume = NULL;
5930 IWineD3DVolume *destVolume = NULL;
5932 for (i = 0 ; i < levels ; ++i) {
5933 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5934 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5935 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5936 IWineD3DVolume_Release(srcVolume);
5937 IWineD3DVolume_Release(destVolume);
5938 if (WINED3D_OK != hr) {
5939 WARN("(%p) : Call to update volume failed\n", This);
5940 return hr;
5944 break;
5946 default:
5947 FIXME("(%p) : Unsupported source and destination type\n", This);
5948 hr = WINED3DERR_INVALIDCALL;
5952 return hr;
5955 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5956 IWineD3DSwapChain *swapChain;
5957 HRESULT hr;
5958 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5959 if(hr == WINED3D_OK) {
5960 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5961 IWineD3DSwapChain_Release(swapChain);
5963 return hr;
5966 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5968 IWineD3DBaseTextureImpl *texture;
5969 DWORD i;
5971 TRACE("(%p) : %p\n", This, pNumPasses);
5973 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5974 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5975 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5976 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5978 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5979 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5980 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5983 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5984 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5986 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5987 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5988 return E_FAIL;
5990 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5991 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5992 return E_FAIL;
5994 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5995 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5996 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5997 return E_FAIL;
6001 /* return a sensible default */
6002 *pNumPasses = 1;
6004 TRACE("returning D3D_OK\n");
6005 return WINED3D_OK;
6008 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6010 int i;
6012 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6013 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6014 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6015 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6017 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6022 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6024 int j;
6025 UINT NewSize;
6026 PALETTEENTRY **palettes;
6028 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6030 if (PaletteNumber >= MAX_PALETTES) {
6031 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6032 return WINED3DERR_INVALIDCALL;
6035 if (PaletteNumber >= This->NumberOfPalettes) {
6036 NewSize = This->NumberOfPalettes;
6037 do {
6038 NewSize *= 2;
6039 } while(PaletteNumber >= NewSize);
6040 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6041 if (!palettes) {
6042 ERR("Out of memory!\n");
6043 return E_OUTOFMEMORY;
6045 This->palettes = palettes;
6046 This->NumberOfPalettes = NewSize;
6049 if (!This->palettes[PaletteNumber]) {
6050 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6051 if (!This->palettes[PaletteNumber]) {
6052 ERR("Out of memory!\n");
6053 return E_OUTOFMEMORY;
6057 for (j = 0; j < 256; ++j) {
6058 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6059 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6060 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6061 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6063 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6064 TRACE("(%p) : returning\n", This);
6065 return WINED3D_OK;
6068 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6070 int j;
6071 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6072 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6073 /* What happens in such situation isn't documented; Native seems to silently abort
6074 on such conditions. Return Invalid Call. */
6075 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6076 return WINED3DERR_INVALIDCALL;
6078 for (j = 0; j < 256; ++j) {
6079 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6080 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6081 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6082 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6084 TRACE("(%p) : returning\n", This);
6085 return WINED3D_OK;
6088 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6091 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6092 (tested with reference rasterizer). Return Invalid Call. */
6093 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6094 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6095 return WINED3DERR_INVALIDCALL;
6097 /*TODO: stateblocks */
6098 if (This->currentPalette != PaletteNumber) {
6099 This->currentPalette = PaletteNumber;
6100 dirtify_p8_texture_samplers(This);
6102 TRACE("(%p) : returning\n", This);
6103 return WINED3D_OK;
6106 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6108 if (PaletteNumber == NULL) {
6109 WARN("(%p) : returning Invalid Call\n", This);
6110 return WINED3DERR_INVALIDCALL;
6112 /*TODO: stateblocks */
6113 *PaletteNumber = This->currentPalette;
6114 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6115 return WINED3D_OK;
6118 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 static BOOL warned;
6121 if (!warned)
6123 FIXME("(%p) : stub\n", This);
6124 warned = TRUE;
6127 This->softwareVertexProcessing = bSoftware;
6128 return WINED3D_OK;
6132 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6134 static BOOL warned;
6135 if (!warned)
6137 FIXME("(%p) : stub\n", This);
6138 warned = TRUE;
6140 return This->softwareVertexProcessing;
6144 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6146 IWineD3DSwapChain *swapChain;
6147 HRESULT hr;
6149 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6151 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6152 if(hr == WINED3D_OK){
6153 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6154 IWineD3DSwapChain_Release(swapChain);
6155 }else{
6156 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6158 return hr;
6162 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6164 static BOOL warned;
6165 if(nSegments != 0.0f) {
6166 if (!warned)
6168 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6169 warned = TRUE;
6172 return WINED3D_OK;
6175 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6177 static BOOL warned;
6178 if (!warned)
6180 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6181 warned = TRUE;
6183 return 0.0f;
6186 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6188 /** TODO: remove casts to IWineD3DSurfaceImpl
6189 * NOTE: move code to surface to accomplish this
6190 ****************************************/
6191 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6192 int srcWidth, srcHeight;
6193 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6194 WINED3DFORMAT destFormat, srcFormat;
6195 UINT destSize;
6196 int srcLeft, destLeft, destTop;
6197 WINED3DPOOL srcPool, destPool;
6198 int offset = 0;
6199 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6200 glDescriptor *glDescription = NULL;
6201 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6202 GLenum dummy;
6203 int sampler;
6204 int bpp;
6205 CONVERT_TYPES convert = NO_CONVERSION;
6207 WINED3DSURFACE_DESC winedesc;
6209 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6210 memset(&winedesc, 0, sizeof(winedesc));
6211 winedesc.Width = &srcSurfaceWidth;
6212 winedesc.Height = &srcSurfaceHeight;
6213 winedesc.Pool = &srcPool;
6214 winedesc.Format = &srcFormat;
6216 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6218 winedesc.Width = &destSurfaceWidth;
6219 winedesc.Height = &destSurfaceHeight;
6220 winedesc.Pool = &destPool;
6221 winedesc.Format = &destFormat;
6222 winedesc.Size = &destSize;
6224 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6226 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6227 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6228 return WINED3DERR_INVALIDCALL;
6231 /* This call loads the opengl surface directly, instead of copying the surface to the
6232 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6233 * copy in sysmem and use regular surface loading.
6235 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6236 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6237 if(convert != NO_CONVERSION) {
6238 return IWineD3DSurface_BltFast(pDestinationSurface,
6239 pDestPoint ? pDestPoint->x : 0,
6240 pDestPoint ? pDestPoint->y : 0,
6241 pSourceSurface, pSourceRect, 0);
6244 if (destFormat == WINED3DFMT_UNKNOWN) {
6245 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6246 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6248 /* Get the update surface description */
6249 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6252 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6254 ENTER_GL();
6255 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6256 checkGLcall("glActiveTextureARB");
6257 LEAVE_GL();
6259 /* Make sure the surface is loaded and up to date */
6260 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6261 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6263 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6265 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6266 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6268 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6269 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6270 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6271 srcLeft = pSourceRect ? pSourceRect->left : 0;
6272 destLeft = pDestPoint ? pDestPoint->x : 0;
6273 destTop = pDestPoint ? pDestPoint->y : 0;
6276 /* This function doesn't support compressed textures
6277 the pitch is just bytesPerPixel * width */
6278 if(srcWidth != srcSurfaceWidth || srcLeft ){
6279 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6280 offset += srcLeft * src_format_desc->byte_count;
6281 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6283 /* TODO DXT formats */
6285 if(pSourceRect != NULL && pSourceRect->top != 0){
6286 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6288 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6289 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6290 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6292 /* Sanity check */
6293 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6295 /* need to lock the surface to get the data */
6296 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6299 ENTER_GL();
6301 /* TODO: Cube and volume support */
6302 if(rowoffset != 0){
6303 /* not a whole row so we have to do it a line at a time */
6304 int j;
6306 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6307 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6309 for (j = destTop; j < (srcHeight + destTop); ++j)
6311 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6312 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6313 data += rowoffset;
6316 } else { /* Full width, so just write out the whole texture */
6317 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6319 if (WINED3DFMT_DXT1 == destFormat ||
6320 WINED3DFMT_DXT2 == destFormat ||
6321 WINED3DFMT_DXT3 == destFormat ||
6322 WINED3DFMT_DXT4 == destFormat ||
6323 WINED3DFMT_DXT5 == destFormat) {
6324 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6325 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6326 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6327 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6328 } if (destFormat != srcFormat) {
6329 FIXME("Updating mixed format compressed texture is not curretly support\n");
6330 } else {
6331 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6332 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6334 } else {
6335 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6339 } else {
6340 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6341 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6344 checkGLcall("glTexSubImage2D");
6346 LEAVE_GL();
6348 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6349 sampler = This->rev_tex_unit_map[0];
6350 if (sampler != -1) {
6351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6354 return WINED3D_OK;
6357 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6359 struct WineD3DRectPatch *patch;
6360 GLenum old_primitive_type;
6361 unsigned int i;
6362 struct list *e;
6363 BOOL found;
6364 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6366 if(!(Handle || pRectPatchInfo)) {
6367 /* TODO: Write a test for the return value, thus the FIXME */
6368 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6369 return WINED3DERR_INVALIDCALL;
6372 if(Handle) {
6373 i = PATCHMAP_HASHFUNC(Handle);
6374 found = FALSE;
6375 LIST_FOR_EACH(e, &This->patches[i]) {
6376 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6377 if(patch->Handle == Handle) {
6378 found = TRUE;
6379 break;
6383 if(!found) {
6384 TRACE("Patch does not exist. Creating a new one\n");
6385 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6386 patch->Handle = Handle;
6387 list_add_head(&This->patches[i], &patch->entry);
6388 } else {
6389 TRACE("Found existing patch %p\n", patch);
6391 } else {
6392 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6393 * attributes we have to tesselate, read back, and draw. This needs a patch
6394 * management structure instance. Create one.
6396 * A possible improvement is to check if a vertex shader is used, and if not directly
6397 * draw the patch.
6399 FIXME("Drawing an uncached patch. This is slow\n");
6400 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6403 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6404 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6405 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6406 HRESULT hr;
6407 TRACE("Tesselation density or patch info changed, retesselating\n");
6409 if(pRectPatchInfo) {
6410 patch->RectPatchInfo = *pRectPatchInfo;
6412 patch->numSegs[0] = pNumSegs[0];
6413 patch->numSegs[1] = pNumSegs[1];
6414 patch->numSegs[2] = pNumSegs[2];
6415 patch->numSegs[3] = pNumSegs[3];
6417 hr = tesselate_rectpatch(This, patch);
6418 if(FAILED(hr)) {
6419 WARN("Patch tesselation failed\n");
6421 /* Do not release the handle to store the params of the patch */
6422 if(!Handle) {
6423 HeapFree(GetProcessHeap(), 0, patch);
6425 return hr;
6429 This->currentPatch = patch;
6430 old_primitive_type = This->stateBlock->gl_primitive_type;
6431 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6432 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6433 This->stateBlock->gl_primitive_type = old_primitive_type;
6434 This->currentPatch = NULL;
6436 /* Destroy uncached patches */
6437 if(!Handle) {
6438 HeapFree(GetProcessHeap(), 0, patch->mem);
6439 HeapFree(GetProcessHeap(), 0, patch);
6441 return WINED3D_OK;
6444 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6446 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6447 FIXME("(%p) : Stub\n", This);
6448 return WINED3D_OK;
6451 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6453 int i;
6454 struct WineD3DRectPatch *patch;
6455 struct list *e;
6456 TRACE("(%p) Handle(%d)\n", This, Handle);
6458 i = PATCHMAP_HASHFUNC(Handle);
6459 LIST_FOR_EACH(e, &This->patches[i]) {
6460 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6461 if(patch->Handle == Handle) {
6462 TRACE("Deleting patch %p\n", patch);
6463 list_remove(&patch->entry);
6464 HeapFree(GetProcessHeap(), 0, patch->mem);
6465 HeapFree(GetProcessHeap(), 0, patch);
6466 return WINED3D_OK;
6470 /* TODO: Write a test for the return value */
6471 FIXME("Attempt to destroy nonexistent patch\n");
6472 return WINED3DERR_INVALIDCALL;
6475 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6476 HRESULT hr;
6477 IWineD3DSwapChain *swapchain;
6479 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6480 if (SUCCEEDED(hr)) {
6481 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6482 return swapchain;
6485 return NULL;
6488 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6489 const WINED3DRECT *rect, const float color[4])
6491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6492 IWineD3DSwapChain *swapchain;
6494 swapchain = get_swapchain(surface);
6495 if (swapchain) {
6496 GLenum buffer;
6498 TRACE("Surface %p is onscreen\n", surface);
6500 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6501 ENTER_GL();
6502 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6503 buffer = surface_get_gl_buffer(surface, swapchain);
6504 glDrawBuffer(buffer);
6505 checkGLcall("glDrawBuffer()");
6506 } else {
6507 TRACE("Surface %p is offscreen\n", surface);
6509 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6510 ENTER_GL();
6511 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6512 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6513 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6514 checkGLcall("glFramebufferRenderbufferEXT");
6517 if (rect) {
6518 glEnable(GL_SCISSOR_TEST);
6519 if(!swapchain) {
6520 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6521 } else {
6522 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6523 rect->x2 - rect->x1, rect->y2 - rect->y1);
6525 checkGLcall("glScissor");
6526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6527 } else {
6528 glDisable(GL_SCISSOR_TEST);
6530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6532 glDisable(GL_BLEND);
6533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6535 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6538 glClearColor(color[0], color[1], color[2], color[3]);
6539 glClear(GL_COLOR_BUFFER_BIT);
6540 checkGLcall("glClear");
6542 if (This->activeContext->current_fbo) {
6543 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6544 } else {
6545 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6546 checkGLcall("glBindFramebuffer()");
6549 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6550 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6551 glDrawBuffer(GL_BACK);
6552 checkGLcall("glDrawBuffer()");
6555 LEAVE_GL();
6558 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6559 unsigned int r, g, b, a;
6560 DWORD ret;
6562 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6563 destfmt == WINED3DFMT_R8G8B8)
6564 return color;
6566 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6568 a = (color & 0xff000000) >> 24;
6569 r = (color & 0x00ff0000) >> 16;
6570 g = (color & 0x0000ff00) >> 8;
6571 b = (color & 0x000000ff) >> 0;
6573 switch(destfmt)
6575 case WINED3DFMT_R5G6B5:
6576 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6577 r = (r * 32) / 256;
6578 g = (g * 64) / 256;
6579 b = (b * 32) / 256;
6580 ret = r << 11;
6581 ret |= g << 5;
6582 ret |= b;
6583 TRACE("Returning %08x\n", ret);
6584 return ret;
6586 case WINED3DFMT_X1R5G5B5:
6587 case WINED3DFMT_A1R5G5B5:
6588 a = (a * 2) / 256;
6589 r = (r * 32) / 256;
6590 g = (g * 32) / 256;
6591 b = (b * 32) / 256;
6592 ret = a << 15;
6593 ret |= r << 10;
6594 ret |= g << 5;
6595 ret |= b << 0;
6596 TRACE("Returning %08x\n", ret);
6597 return ret;
6599 case WINED3DFMT_A8_UNORM:
6600 TRACE("Returning %08x\n", a);
6601 return a;
6603 case WINED3DFMT_X4R4G4B4:
6604 case WINED3DFMT_A4R4G4B4:
6605 a = (a * 16) / 256;
6606 r = (r * 16) / 256;
6607 g = (g * 16) / 256;
6608 b = (b * 16) / 256;
6609 ret = a << 12;
6610 ret |= r << 8;
6611 ret |= g << 4;
6612 ret |= b << 0;
6613 TRACE("Returning %08x\n", ret);
6614 return ret;
6616 case WINED3DFMT_R3G3B2:
6617 r = (r * 8) / 256;
6618 g = (g * 8) / 256;
6619 b = (b * 4) / 256;
6620 ret = r << 5;
6621 ret |= g << 2;
6622 ret |= b << 0;
6623 TRACE("Returning %08x\n", ret);
6624 return ret;
6626 case WINED3DFMT_X8B8G8R8:
6627 case WINED3DFMT_R8G8B8A8_UNORM:
6628 ret = a << 24;
6629 ret |= b << 16;
6630 ret |= g << 8;
6631 ret |= r << 0;
6632 TRACE("Returning %08x\n", ret);
6633 return ret;
6635 case WINED3DFMT_A2R10G10B10:
6636 a = (a * 4) / 256;
6637 r = (r * 1024) / 256;
6638 g = (g * 1024) / 256;
6639 b = (b * 1024) / 256;
6640 ret = a << 30;
6641 ret |= r << 20;
6642 ret |= g << 10;
6643 ret |= b << 0;
6644 TRACE("Returning %08x\n", ret);
6645 return ret;
6647 case WINED3DFMT_R10G10B10A2_UNORM:
6648 a = (a * 4) / 256;
6649 r = (r * 1024) / 256;
6650 g = (g * 1024) / 256;
6651 b = (b * 1024) / 256;
6652 ret = a << 30;
6653 ret |= b << 20;
6654 ret |= g << 10;
6655 ret |= r << 0;
6656 TRACE("Returning %08x\n", ret);
6657 return ret;
6659 default:
6660 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6661 return 0;
6665 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6667 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6668 WINEDDBLTFX BltFx;
6669 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6671 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6672 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6673 return WINED3DERR_INVALIDCALL;
6676 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6677 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6678 color_fill_fbo(iface, pSurface, pRect, c);
6679 return WINED3D_OK;
6680 } else {
6681 /* Just forward this to the DirectDraw blitting engine */
6682 memset(&BltFx, 0, sizeof(BltFx));
6683 BltFx.dwSize = sizeof(BltFx);
6684 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6685 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6686 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6690 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6691 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6693 IWineD3DResource *resource;
6694 IWineD3DSurface *surface;
6695 HRESULT hr;
6697 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6698 if (FAILED(hr))
6700 ERR("Failed to get resource, hr %#x\n", hr);
6701 return;
6704 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6706 FIXME("Only supported on surface resources\n");
6707 IWineD3DResource_Release(resource);
6708 return;
6711 surface = (IWineD3DSurface *)resource;
6713 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6715 color_fill_fbo(iface, surface, NULL, color);
6717 else
6719 WINEDDBLTFX BltFx;
6720 WINED3DCOLOR c;
6722 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6724 c = ((DWORD)(color[2] * 255.0));
6725 c |= ((DWORD)(color[1] * 255.0)) << 8;
6726 c |= ((DWORD)(color[0] * 255.0)) << 16;
6727 c |= ((DWORD)(color[3] * 255.0)) << 24;
6729 /* Just forward this to the DirectDraw blitting engine */
6730 memset(&BltFx, 0, sizeof(BltFx));
6731 BltFx.dwSize = sizeof(BltFx);
6732 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6733 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6734 if (FAILED(hr))
6736 ERR("Blt failed, hr %#x\n", hr);
6740 IWineD3DResource_Release(resource);
6743 /* rendertarget and depth stencil functions */
6744 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6747 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6748 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6749 return WINED3DERR_INVALIDCALL;
6752 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6753 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6754 /* Note inc ref on returned surface */
6755 if(*ppRenderTarget != NULL)
6756 IWineD3DSurface_AddRef(*ppRenderTarget);
6757 return WINED3D_OK;
6760 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6762 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6763 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6764 IWineD3DSwapChainImpl *Swapchain;
6765 HRESULT hr;
6767 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6769 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6770 if(hr != WINED3D_OK) {
6771 ERR("Can't get the swapchain\n");
6772 return hr;
6775 /* Make sure to release the swapchain */
6776 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6778 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6779 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6780 return WINED3DERR_INVALIDCALL;
6782 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6783 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6784 return WINED3DERR_INVALIDCALL;
6787 if(Swapchain->frontBuffer != Front) {
6788 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6790 if(Swapchain->frontBuffer)
6792 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6793 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6795 Swapchain->frontBuffer = Front;
6797 if(Swapchain->frontBuffer) {
6798 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6799 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6803 if(Back && !Swapchain->backBuffer) {
6804 /* We need memory for the back buffer array - only one back buffer this way */
6805 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6806 if(!Swapchain->backBuffer) {
6807 ERR("Out of memory\n");
6808 return E_OUTOFMEMORY;
6812 if(Swapchain->backBuffer[0] != Back) {
6813 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6815 /* What to do about the context here in the case of multithreading? Not sure.
6816 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6818 ENTER_GL();
6819 if(!Swapchain->backBuffer[0]) {
6820 /* GL was told to draw to the front buffer at creation,
6821 * undo that
6823 glDrawBuffer(GL_BACK);
6824 checkGLcall("glDrawBuffer(GL_BACK)");
6825 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6826 Swapchain->presentParms.BackBufferCount = 1;
6827 } else if (!Back) {
6828 /* That makes problems - disable for now */
6829 /* glDrawBuffer(GL_FRONT); */
6830 checkGLcall("glDrawBuffer(GL_FRONT)");
6831 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6832 Swapchain->presentParms.BackBufferCount = 0;
6834 LEAVE_GL();
6836 if(Swapchain->backBuffer[0])
6838 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6839 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6841 Swapchain->backBuffer[0] = Back;
6843 if(Swapchain->backBuffer[0]) {
6844 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6845 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6846 } else {
6847 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6848 Swapchain->backBuffer = NULL;
6853 return WINED3D_OK;
6856 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6858 *ppZStencilSurface = This->stencilBufferTarget;
6859 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6861 if(*ppZStencilSurface != NULL) {
6862 /* Note inc ref on returned surface */
6863 IWineD3DSurface_AddRef(*ppZStencilSurface);
6864 return WINED3D_OK;
6865 } else {
6866 return WINED3DERR_NOTFOUND;
6870 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6871 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6874 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6875 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6876 GLenum gl_filter;
6877 POINT offset = {0, 0};
6879 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6880 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6881 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6882 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6884 switch (filter) {
6885 case WINED3DTEXF_LINEAR:
6886 gl_filter = GL_LINEAR;
6887 break;
6889 default:
6890 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6891 case WINED3DTEXF_NONE:
6892 case WINED3DTEXF_POINT:
6893 gl_filter = GL_NEAREST;
6894 break;
6897 /* Attach src surface to src fbo */
6898 src_swapchain = get_swapchain(src_surface);
6899 if (src_swapchain) {
6900 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6902 TRACE("Source surface %p is onscreen\n", src_surface);
6903 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6904 /* Make sure the drawable is up to date. In the offscreen case
6905 * attach_surface_fbo() implicitly takes care of this. */
6906 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6908 if(buffer == GL_FRONT) {
6909 RECT windowsize;
6910 UINT h;
6911 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6912 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6913 h = windowsize.bottom - windowsize.top;
6914 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6915 src_rect->y1 = offset.y + h - src_rect->y1;
6916 src_rect->y2 = offset.y + h - src_rect->y2;
6917 } else {
6918 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6919 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6922 ENTER_GL();
6923 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6924 glReadBuffer(buffer);
6925 checkGLcall("glReadBuffer()");
6926 } else {
6927 TRACE("Source surface %p is offscreen\n", src_surface);
6928 ENTER_GL();
6929 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6930 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6931 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6932 checkGLcall("glReadBuffer()");
6933 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6934 checkGLcall("glFramebufferRenderbufferEXT");
6936 LEAVE_GL();
6938 /* Attach dst surface to dst fbo */
6939 dst_swapchain = get_swapchain(dst_surface);
6940 if (dst_swapchain) {
6941 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6943 TRACE("Destination surface %p is onscreen\n", dst_surface);
6944 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6945 /* Make sure the drawable is up to date. In the offscreen case
6946 * attach_surface_fbo() implicitly takes care of this. */
6947 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6949 if(buffer == GL_FRONT) {
6950 RECT windowsize;
6951 UINT h;
6952 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6953 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6954 h = windowsize.bottom - windowsize.top;
6955 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6956 dst_rect->y1 = offset.y + h - dst_rect->y1;
6957 dst_rect->y2 = offset.y + h - dst_rect->y2;
6958 } else {
6959 /* Screen coords = window coords, surface height = window height */
6960 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6961 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6964 ENTER_GL();
6965 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6966 glDrawBuffer(buffer);
6967 checkGLcall("glDrawBuffer()");
6968 } else {
6969 TRACE("Destination surface %p is offscreen\n", dst_surface);
6971 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6972 if(!src_swapchain) {
6973 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6976 ENTER_GL();
6977 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6978 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6979 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6980 checkGLcall("glDrawBuffer()");
6981 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6982 checkGLcall("glFramebufferRenderbufferEXT");
6984 glDisable(GL_SCISSOR_TEST);
6985 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6987 if (flip) {
6988 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6989 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6990 checkGLcall("glBlitFramebuffer()");
6991 } else {
6992 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6993 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6994 checkGLcall("glBlitFramebuffer()");
6997 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6999 if (This->activeContext->current_fbo) {
7000 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7001 } else {
7002 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7003 checkGLcall("glBindFramebuffer()");
7006 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7007 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7008 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7009 glDrawBuffer(GL_BACK);
7010 checkGLcall("glDrawBuffer()");
7012 LEAVE_GL();
7015 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7017 WINED3DVIEWPORT viewport;
7019 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7021 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7022 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7023 This, RenderTargetIndex, GL_LIMITS(buffers));
7024 return WINED3DERR_INVALIDCALL;
7027 /* MSDN says that null disables the render target
7028 but a device must always be associated with a render target
7029 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7031 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7032 FIXME("Trying to set render target 0 to NULL\n");
7033 return WINED3DERR_INVALIDCALL;
7035 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7036 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);
7037 return WINED3DERR_INVALIDCALL;
7040 /* If we are trying to set what we already have, don't bother */
7041 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7042 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7043 return WINED3D_OK;
7045 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7046 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7047 This->render_targets[RenderTargetIndex] = pRenderTarget;
7049 /* Render target 0 is special */
7050 if(RenderTargetIndex == 0) {
7051 /* Finally, reset the viewport as the MSDN states. */
7052 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7053 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7054 viewport.X = 0;
7055 viewport.Y = 0;
7056 viewport.MaxZ = 1.0f;
7057 viewport.MinZ = 0.0f;
7058 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7059 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7060 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7064 return WINED3D_OK;
7067 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7069 HRESULT hr = WINED3D_OK;
7070 IWineD3DSurface *tmp;
7072 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7074 if (pNewZStencil == This->stencilBufferTarget) {
7075 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7076 } else {
7077 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7078 * depending on the renter target implementation being used.
7079 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7080 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7081 * stencil buffer and incur an extra memory overhead
7082 ******************************************************/
7084 if (This->stencilBufferTarget) {
7085 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7086 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7087 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7088 } else {
7089 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7090 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7091 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7095 tmp = This->stencilBufferTarget;
7096 This->stencilBufferTarget = pNewZStencil;
7097 /* should we be calling the parent or the wined3d surface? */
7098 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7099 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7100 hr = WINED3D_OK;
7102 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7103 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7110 return hr;
7113 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7114 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7116 /* TODO: the use of Impl is deprecated. */
7117 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7118 WINED3DLOCKED_RECT lockedRect;
7120 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7122 /* some basic validation checks */
7123 if(This->cursorTexture) {
7124 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7125 ENTER_GL();
7126 glDeleteTextures(1, &This->cursorTexture);
7127 LEAVE_GL();
7128 This->cursorTexture = 0;
7131 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7132 This->haveHardwareCursor = TRUE;
7133 else
7134 This->haveHardwareCursor = FALSE;
7136 if(pCursorBitmap) {
7137 WINED3DLOCKED_RECT rect;
7139 /* MSDN: Cursor must be A8R8G8B8 */
7140 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7142 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7143 return WINED3DERR_INVALIDCALL;
7146 /* MSDN: Cursor must be smaller than the display mode */
7147 if(pSur->currentDesc.Width > This->ddraw_width ||
7148 pSur->currentDesc.Height > This->ddraw_height) {
7149 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);
7150 return WINED3DERR_INVALIDCALL;
7153 if (!This->haveHardwareCursor) {
7154 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7156 /* Do not store the surface's pointer because the application may
7157 * release it after setting the cursor image. Windows doesn't
7158 * addref the set surface, so we can't do this either without
7159 * creating circular refcount dependencies. Copy out the gl texture
7160 * instead.
7162 This->cursorWidth = pSur->currentDesc.Width;
7163 This->cursorHeight = pSur->currentDesc.Height;
7164 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7166 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7167 char *mem, *bits = rect.pBits;
7168 GLint intfmt = glDesc->glInternal;
7169 GLint format = glDesc->glFormat;
7170 GLint type = glDesc->glType;
7171 INT height = This->cursorHeight;
7172 INT width = This->cursorWidth;
7173 INT bpp = glDesc->byte_count;
7174 INT i, sampler;
7176 /* Reformat the texture memory (pitch and width can be
7177 * different) */
7178 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7179 for(i = 0; i < height; i++)
7180 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7181 IWineD3DSurface_UnlockRect(pCursorBitmap);
7182 ENTER_GL();
7184 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7185 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7186 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7189 /* Make sure that a proper texture unit is selected */
7190 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7191 checkGLcall("glActiveTextureARB");
7192 sampler = This->rev_tex_unit_map[0];
7193 if (sampler != -1) {
7194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7196 /* Create a new cursor texture */
7197 glGenTextures(1, &This->cursorTexture);
7198 checkGLcall("glGenTextures");
7199 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7200 checkGLcall("glBindTexture");
7201 /* Copy the bitmap memory into the cursor texture */
7202 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7203 HeapFree(GetProcessHeap(), 0, mem);
7204 checkGLcall("glTexImage2D");
7206 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7207 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7208 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7211 LEAVE_GL();
7213 else
7215 FIXME("A cursor texture was not returned.\n");
7216 This->cursorTexture = 0;
7219 else
7221 /* Draw a hardware cursor */
7222 ICONINFO cursorInfo;
7223 HCURSOR cursor;
7224 /* Create and clear maskBits because it is not needed for
7225 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7226 * chunks. */
7227 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7228 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7229 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7230 WINED3DLOCK_NO_DIRTY_UPDATE |
7231 WINED3DLOCK_READONLY
7233 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7234 pSur->currentDesc.Height);
7236 cursorInfo.fIcon = FALSE;
7237 cursorInfo.xHotspot = XHotSpot;
7238 cursorInfo.yHotspot = YHotSpot;
7239 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7240 pSur->currentDesc.Height, 1,
7241 1, &maskBits);
7242 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7243 pSur->currentDesc.Height, 1,
7244 32, lockedRect.pBits);
7245 IWineD3DSurface_UnlockRect(pCursorBitmap);
7246 /* Create our cursor and clean up. */
7247 cursor = CreateIconIndirect(&cursorInfo);
7248 SetCursor(cursor);
7249 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7250 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7251 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7252 This->hardwareCursor = cursor;
7253 HeapFree(GetProcessHeap(), 0, maskBits);
7257 This->xHotSpot = XHotSpot;
7258 This->yHotSpot = YHotSpot;
7259 return WINED3D_OK;
7262 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7264 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7266 This->xScreenSpace = XScreenSpace;
7267 This->yScreenSpace = YScreenSpace;
7269 return;
7273 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7275 BOOL oldVisible = This->bCursorVisible;
7276 POINT pt;
7278 TRACE("(%p) : visible(%d)\n", This, bShow);
7281 * When ShowCursor is first called it should make the cursor appear at the OS's last
7282 * known cursor position. Because of this, some applications just repetitively call
7283 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7285 GetCursorPos(&pt);
7286 This->xScreenSpace = pt.x;
7287 This->yScreenSpace = pt.y;
7289 if (This->haveHardwareCursor) {
7290 This->bCursorVisible = bShow;
7291 if (bShow)
7292 SetCursor(This->hardwareCursor);
7293 else
7294 SetCursor(NULL);
7296 else
7298 if (This->cursorTexture)
7299 This->bCursorVisible = bShow;
7302 return oldVisible;
7305 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7307 IWineD3DResourceImpl *resource;
7308 TRACE("(%p) : state (%u)\n", This, This->state);
7310 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7311 switch (This->state) {
7312 case WINED3D_OK:
7313 return WINED3D_OK;
7314 case WINED3DERR_DEVICELOST:
7316 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7317 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7318 return WINED3DERR_DEVICENOTRESET;
7320 return WINED3DERR_DEVICELOST;
7322 case WINED3DERR_DRIVERINTERNALERROR:
7323 return WINED3DERR_DRIVERINTERNALERROR;
7326 /* Unknown state */
7327 return WINED3DERR_DRIVERINTERNALERROR;
7331 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7333 /** FIXME: Resource tracking needs to be done,
7334 * The closes we can do to this is set the priorities of all managed textures low
7335 * and then reset them.
7336 ***********************************************************/
7337 FIXME("(%p) : stub\n", This);
7338 return WINED3D_OK;
7341 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7343 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7345 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7346 if(surface->Flags & SFLAG_DIBSECTION) {
7347 /* Release the DC */
7348 SelectObject(surface->hDC, surface->dib.holdbitmap);
7349 DeleteDC(surface->hDC);
7350 /* Release the DIB section */
7351 DeleteObject(surface->dib.DIBsection);
7352 surface->dib.bitmap_data = NULL;
7353 surface->resource.allocatedMemory = NULL;
7354 surface->Flags &= ~SFLAG_DIBSECTION;
7356 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7357 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7358 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7359 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7360 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7361 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7362 } else {
7363 surface->pow2Width = surface->pow2Height = 1;
7364 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7365 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7367 surface->glRect.left = 0;
7368 surface->glRect.top = 0;
7369 surface->glRect.right = surface->pow2Width;
7370 surface->glRect.bottom = surface->pow2Height;
7372 if(surface->glDescription.textureName) {
7373 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7374 ENTER_GL();
7375 glDeleteTextures(1, &surface->glDescription.textureName);
7376 LEAVE_GL();
7377 surface->glDescription.textureName = 0;
7378 surface->Flags &= ~SFLAG_CLIENT;
7380 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7381 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7382 surface->Flags |= SFLAG_NONPOW2;
7383 } else {
7384 surface->Flags &= ~SFLAG_NONPOW2;
7386 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7387 surface->resource.allocatedMemory = NULL;
7388 surface->resource.heapMemory = NULL;
7389 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7390 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7391 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7392 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7393 } else {
7394 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7398 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7399 TRACE("Unloading resource %p\n", resource);
7400 IWineD3DResource_UnLoad(resource);
7401 IWineD3DResource_Release(resource);
7402 return S_OK;
7405 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7407 UINT i, count;
7408 WINED3DDISPLAYMODE m;
7409 HRESULT hr;
7411 /* All Windowed modes are supported, as is leaving the current mode */
7412 if(pp->Windowed) return TRUE;
7413 if(!pp->BackBufferWidth) return TRUE;
7414 if(!pp->BackBufferHeight) return TRUE;
7416 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7417 for(i = 0; i < count; i++) {
7418 memset(&m, 0, sizeof(m));
7419 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7420 if(FAILED(hr)) {
7421 ERR("EnumAdapterModes failed\n");
7423 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7424 /* Mode found, it is supported */
7425 return TRUE;
7428 /* Mode not found -> not supported */
7429 return FALSE;
7432 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7434 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7435 UINT i;
7436 IWineD3DBaseShaderImpl *shader;
7438 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7439 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7440 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7443 ENTER_GL();
7444 if(This->depth_blt_texture) {
7445 glDeleteTextures(1, &This->depth_blt_texture);
7446 This->depth_blt_texture = 0;
7448 if (This->depth_blt_rb) {
7449 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7450 This->depth_blt_rb = 0;
7451 This->depth_blt_rb_w = 0;
7452 This->depth_blt_rb_h = 0;
7454 LEAVE_GL();
7456 This->blitter->free_private(iface);
7457 This->frag_pipe->free_private(iface);
7458 This->shader_backend->shader_free_private(iface);
7460 ENTER_GL();
7461 for (i = 0; i < GL_LIMITS(textures); i++) {
7462 /* Textures are recreated below */
7463 glDeleteTextures(1, &This->dummyTextureName[i]);
7464 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7465 This->dummyTextureName[i] = 0;
7467 LEAVE_GL();
7469 while(This->numContexts) {
7470 DestroyContext(This, This->contexts[0]);
7472 This->activeContext = NULL;
7473 HeapFree(GetProcessHeap(), 0, swapchain->context);
7474 swapchain->context = NULL;
7475 swapchain->num_contexts = 0;
7478 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7480 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7481 HRESULT hr;
7482 IWineD3DSurfaceImpl *target;
7484 /* Recreate the primary swapchain's context */
7485 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7486 if(swapchain->backBuffer) {
7487 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7488 } else {
7489 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7491 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7492 &swapchain->presentParms);
7493 swapchain->num_contexts = 1;
7494 This->activeContext = swapchain->context[0];
7496 create_dummy_textures(This);
7498 hr = This->shader_backend->shader_alloc_private(iface);
7499 if(FAILED(hr)) {
7500 ERR("Failed to recreate shader private data\n");
7501 goto err_out;
7503 hr = This->frag_pipe->alloc_private(iface);
7504 if(FAILED(hr)) {
7505 TRACE("Fragment pipeline private data couldn't be allocated\n");
7506 goto err_out;
7508 hr = This->blitter->alloc_private(iface);
7509 if(FAILED(hr)) {
7510 TRACE("Blitter private data couldn't be allocated\n");
7511 goto err_out;
7514 return WINED3D_OK;
7516 err_out:
7517 This->blitter->free_private(iface);
7518 This->frag_pipe->free_private(iface);
7519 This->shader_backend->shader_free_private(iface);
7520 return hr;
7523 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7525 IWineD3DSwapChainImpl *swapchain;
7526 HRESULT hr;
7527 BOOL DisplayModeChanged = FALSE;
7528 WINED3DDISPLAYMODE mode;
7529 TRACE("(%p)\n", This);
7531 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7532 if(FAILED(hr)) {
7533 ERR("Failed to get the first implicit swapchain\n");
7534 return hr;
7537 if(!is_display_mode_supported(This, pPresentationParameters)) {
7538 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7539 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7540 pPresentationParameters->BackBufferHeight);
7541 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7542 return WINED3DERR_INVALIDCALL;
7545 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7546 * on an existing gl context, so there's no real need for recreation.
7548 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7550 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7552 TRACE("New params:\n");
7553 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7554 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7555 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7556 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7557 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7558 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7559 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7560 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7561 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7562 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7563 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7564 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7565 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7567 /* No special treatment of these parameters. Just store them */
7568 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7569 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7570 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7571 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7573 /* What to do about these? */
7574 if(pPresentationParameters->BackBufferCount != 0 &&
7575 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7576 ERR("Cannot change the back buffer count yet\n");
7578 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7579 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7580 ERR("Cannot change the back buffer format yet\n");
7582 if(pPresentationParameters->hDeviceWindow != NULL &&
7583 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7584 ERR("Cannot change the device window yet\n");
7586 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7587 HRESULT hrc;
7589 TRACE("Creating the depth stencil buffer\n");
7591 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7592 This->parent,
7593 pPresentationParameters->BackBufferWidth,
7594 pPresentationParameters->BackBufferHeight,
7595 pPresentationParameters->AutoDepthStencilFormat,
7596 pPresentationParameters->MultiSampleType,
7597 pPresentationParameters->MultiSampleQuality,
7598 FALSE,
7599 &This->auto_depth_stencil_buffer);
7601 if (FAILED(hrc)) {
7602 ERR("Failed to create the depth stencil buffer\n");
7603 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7604 return WINED3DERR_INVALIDCALL;
7608 /* Reset the depth stencil */
7609 if (pPresentationParameters->EnableAutoDepthStencil)
7610 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7611 else
7612 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7614 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7616 if(pPresentationParameters->Windowed) {
7617 mode.Width = swapchain->orig_width;
7618 mode.Height = swapchain->orig_height;
7619 mode.RefreshRate = 0;
7620 mode.Format = swapchain->presentParms.BackBufferFormat;
7621 } else {
7622 mode.Width = pPresentationParameters->BackBufferWidth;
7623 mode.Height = pPresentationParameters->BackBufferHeight;
7624 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7625 mode.Format = swapchain->presentParms.BackBufferFormat;
7628 /* Should Width == 800 && Height == 0 set 800x600? */
7629 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7630 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7631 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7633 UINT i;
7635 if(!pPresentationParameters->Windowed) {
7636 DisplayModeChanged = TRUE;
7638 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7639 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7641 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7642 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7643 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7645 if(This->auto_depth_stencil_buffer) {
7646 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7650 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7651 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7652 DisplayModeChanged) {
7654 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7656 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7657 if(swapchain->presentParms.Windowed) {
7658 /* switch from windowed to fs */
7659 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7660 pPresentationParameters->BackBufferWidth,
7661 pPresentationParameters->BackBufferHeight);
7662 } else {
7663 /* Fullscreen -> fullscreen mode change */
7664 MoveWindow(swapchain->win_handle, 0, 0,
7665 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7666 TRUE);
7668 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7669 /* Fullscreen -> windowed switch */
7670 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7672 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7673 } else if(!pPresentationParameters->Windowed) {
7674 DWORD style = This->style, exStyle = This->exStyle;
7675 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7676 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7677 * Reset to clear up their mess. Guild Wars also loses the device during that.
7679 This->style = 0;
7680 This->exStyle = 0;
7681 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7682 pPresentationParameters->BackBufferWidth,
7683 pPresentationParameters->BackBufferHeight);
7684 This->style = style;
7685 This->exStyle = exStyle;
7688 TRACE("Resetting stateblock\n");
7689 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7690 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7692 /* Note: No parent needed for initial internal stateblock */
7693 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7694 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7695 else TRACE("Created stateblock %p\n", This->stateBlock);
7696 This->updateStateBlock = This->stateBlock;
7697 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7699 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7700 if(FAILED(hr)) {
7701 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7704 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7705 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7707 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7708 * first use
7710 return hr;
7713 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7715 /** FIXME: always true at the moment **/
7716 if(!bEnableDialogs) {
7717 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7719 return WINED3D_OK;
7723 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7725 TRACE("(%p) : pParameters %p\n", This, pParameters);
7727 *pParameters = This->createParms;
7728 return WINED3D_OK;
7731 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7732 IWineD3DSwapChain *swapchain;
7734 TRACE("Relaying to swapchain\n");
7736 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7737 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7738 IWineD3DSwapChain_Release(swapchain);
7740 return;
7743 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7744 IWineD3DSwapChain *swapchain;
7746 TRACE("Relaying to swapchain\n");
7748 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7749 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7750 IWineD3DSwapChain_Release(swapchain);
7752 return;
7756 /** ********************************************************
7757 * Notification functions
7758 ** ********************************************************/
7759 /** This function must be called in the release of a resource when ref == 0,
7760 * the contents of resource must still be correct,
7761 * any handles to other resource held by the caller must be closed
7762 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7763 *****************************************************/
7764 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7766 TRACE("(%p) : Adding resource %p\n", This, resource);
7768 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7771 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7773 TRACE("(%p) : Removing resource %p\n", This, resource);
7775 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7778 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7780 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7781 int counter;
7783 TRACE("(%p) : resource %p\n", This, resource);
7785 context_resource_released((IWineD3DDevice *)This, resource, type);
7787 switch (type) {
7788 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7789 case WINED3DRTYPE_SURFACE: {
7790 unsigned int i;
7792 /* Cleanup any FBO attachments if d3d is enabled */
7793 if(This->d3d_initialized) {
7794 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7795 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7797 TRACE("Last active render target destroyed\n");
7798 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7799 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7800 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7801 * and the lastActiveRenderTarget member shouldn't matter
7803 if(swapchain) {
7804 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7805 TRACE("Activating primary back buffer\n");
7806 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7807 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7808 /* Single buffering environment */
7809 TRACE("Activating primary front buffer\n");
7810 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7811 } else {
7812 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7813 /* Implicit render target destroyed, that means the device is being destroyed
7814 * whatever we set here, it shouldn't matter
7816 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7818 } else {
7819 /* May happen during ddraw uninitialization */
7820 TRACE("Render target set, but swapchain does not exist!\n");
7821 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7825 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7826 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7827 This->render_targets[i] = NULL;
7830 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7831 This->stencilBufferTarget = NULL;
7835 break;
7837 case WINED3DRTYPE_TEXTURE:
7838 case WINED3DRTYPE_CUBETEXTURE:
7839 case WINED3DRTYPE_VOLUMETEXTURE:
7840 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7841 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7842 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7843 This->stateBlock->textures[counter] = NULL;
7845 if (This->updateStateBlock != This->stateBlock ){
7846 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7847 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7848 This->updateStateBlock->textures[counter] = NULL;
7852 break;
7853 case WINED3DRTYPE_VOLUME:
7854 /* TODO: nothing really? */
7855 break;
7856 case WINED3DRTYPE_BUFFER:
7858 int streamNumber;
7859 TRACE("Cleaning up stream pointers\n");
7861 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7862 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7863 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7865 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7866 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7867 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7868 This->updateStateBlock->streamSource[streamNumber] = 0;
7869 /* Set changed flag? */
7872 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) */
7873 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7874 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7875 This->stateBlock->streamSource[streamNumber] = 0;
7880 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7881 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7882 This->updateStateBlock->pIndexData = NULL;
7885 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7886 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7887 This->stateBlock->pIndexData = NULL;
7891 break;
7893 default:
7894 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7895 break;
7899 /* Remove the resource from the resourceStore */
7900 device_resource_remove(This, resource);
7902 TRACE("Resource released\n");
7906 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7908 IWineD3DResourceImpl *resource, *cursor;
7909 HRESULT ret;
7910 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7912 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7913 TRACE("enumerating resource %p\n", resource);
7914 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7915 ret = pCallback((IWineD3DResource *) resource, pData);
7916 if(ret == S_FALSE) {
7917 TRACE("Canceling enumeration\n");
7918 break;
7921 return WINED3D_OK;
7924 /**********************************************************
7925 * IWineD3DDevice VTbl follows
7926 **********************************************************/
7928 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7930 /*** IUnknown methods ***/
7931 IWineD3DDeviceImpl_QueryInterface,
7932 IWineD3DDeviceImpl_AddRef,
7933 IWineD3DDeviceImpl_Release,
7934 /*** IWineD3DDevice methods ***/
7935 IWineD3DDeviceImpl_GetParent,
7936 /*** Creation methods**/
7937 IWineD3DDeviceImpl_CreateBuffer,
7938 IWineD3DDeviceImpl_CreateVertexBuffer,
7939 IWineD3DDeviceImpl_CreateIndexBuffer,
7940 IWineD3DDeviceImpl_CreateStateBlock,
7941 IWineD3DDeviceImpl_CreateSurface,
7942 IWineD3DDeviceImpl_CreateRendertargetView,
7943 IWineD3DDeviceImpl_CreateTexture,
7944 IWineD3DDeviceImpl_CreateVolumeTexture,
7945 IWineD3DDeviceImpl_CreateVolume,
7946 IWineD3DDeviceImpl_CreateCubeTexture,
7947 IWineD3DDeviceImpl_CreateQuery,
7948 IWineD3DDeviceImpl_CreateSwapChain,
7949 IWineD3DDeviceImpl_CreateVertexDeclaration,
7950 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7951 IWineD3DDeviceImpl_CreateVertexShader,
7952 IWineD3DDeviceImpl_CreatePixelShader,
7953 IWineD3DDeviceImpl_CreatePalette,
7954 /*** Odd functions **/
7955 IWineD3DDeviceImpl_Init3D,
7956 IWineD3DDeviceImpl_InitGDI,
7957 IWineD3DDeviceImpl_Uninit3D,
7958 IWineD3DDeviceImpl_UninitGDI,
7959 IWineD3DDeviceImpl_SetMultithreaded,
7960 IWineD3DDeviceImpl_EvictManagedResources,
7961 IWineD3DDeviceImpl_GetAvailableTextureMem,
7962 IWineD3DDeviceImpl_GetBackBuffer,
7963 IWineD3DDeviceImpl_GetCreationParameters,
7964 IWineD3DDeviceImpl_GetDeviceCaps,
7965 IWineD3DDeviceImpl_GetDirect3D,
7966 IWineD3DDeviceImpl_GetDisplayMode,
7967 IWineD3DDeviceImpl_SetDisplayMode,
7968 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7969 IWineD3DDeviceImpl_GetRasterStatus,
7970 IWineD3DDeviceImpl_GetSwapChain,
7971 IWineD3DDeviceImpl_Reset,
7972 IWineD3DDeviceImpl_SetDialogBoxMode,
7973 IWineD3DDeviceImpl_SetCursorProperties,
7974 IWineD3DDeviceImpl_SetCursorPosition,
7975 IWineD3DDeviceImpl_ShowCursor,
7976 IWineD3DDeviceImpl_TestCooperativeLevel,
7977 /*** Getters and setters **/
7978 IWineD3DDeviceImpl_SetClipPlane,
7979 IWineD3DDeviceImpl_GetClipPlane,
7980 IWineD3DDeviceImpl_SetClipStatus,
7981 IWineD3DDeviceImpl_GetClipStatus,
7982 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7983 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7984 IWineD3DDeviceImpl_SetDepthStencilSurface,
7985 IWineD3DDeviceImpl_GetDepthStencilSurface,
7986 IWineD3DDeviceImpl_SetGammaRamp,
7987 IWineD3DDeviceImpl_GetGammaRamp,
7988 IWineD3DDeviceImpl_SetIndices,
7989 IWineD3DDeviceImpl_GetIndices,
7990 IWineD3DDeviceImpl_SetBaseVertexIndex,
7991 IWineD3DDeviceImpl_GetBaseVertexIndex,
7992 IWineD3DDeviceImpl_SetLight,
7993 IWineD3DDeviceImpl_GetLight,
7994 IWineD3DDeviceImpl_SetLightEnable,
7995 IWineD3DDeviceImpl_GetLightEnable,
7996 IWineD3DDeviceImpl_SetMaterial,
7997 IWineD3DDeviceImpl_GetMaterial,
7998 IWineD3DDeviceImpl_SetNPatchMode,
7999 IWineD3DDeviceImpl_GetNPatchMode,
8000 IWineD3DDeviceImpl_SetPaletteEntries,
8001 IWineD3DDeviceImpl_GetPaletteEntries,
8002 IWineD3DDeviceImpl_SetPixelShader,
8003 IWineD3DDeviceImpl_GetPixelShader,
8004 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8005 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8006 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8007 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8008 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8009 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8010 IWineD3DDeviceImpl_SetRenderState,
8011 IWineD3DDeviceImpl_GetRenderState,
8012 IWineD3DDeviceImpl_SetRenderTarget,
8013 IWineD3DDeviceImpl_GetRenderTarget,
8014 IWineD3DDeviceImpl_SetFrontBackBuffers,
8015 IWineD3DDeviceImpl_SetSamplerState,
8016 IWineD3DDeviceImpl_GetSamplerState,
8017 IWineD3DDeviceImpl_SetScissorRect,
8018 IWineD3DDeviceImpl_GetScissorRect,
8019 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8020 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8021 IWineD3DDeviceImpl_SetStreamSource,
8022 IWineD3DDeviceImpl_GetStreamSource,
8023 IWineD3DDeviceImpl_SetStreamSourceFreq,
8024 IWineD3DDeviceImpl_GetStreamSourceFreq,
8025 IWineD3DDeviceImpl_SetTexture,
8026 IWineD3DDeviceImpl_GetTexture,
8027 IWineD3DDeviceImpl_SetTextureStageState,
8028 IWineD3DDeviceImpl_GetTextureStageState,
8029 IWineD3DDeviceImpl_SetTransform,
8030 IWineD3DDeviceImpl_GetTransform,
8031 IWineD3DDeviceImpl_SetVertexDeclaration,
8032 IWineD3DDeviceImpl_GetVertexDeclaration,
8033 IWineD3DDeviceImpl_SetVertexShader,
8034 IWineD3DDeviceImpl_GetVertexShader,
8035 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8036 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8037 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8038 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8039 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8040 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8041 IWineD3DDeviceImpl_SetViewport,
8042 IWineD3DDeviceImpl_GetViewport,
8043 IWineD3DDeviceImpl_MultiplyTransform,
8044 IWineD3DDeviceImpl_ValidateDevice,
8045 IWineD3DDeviceImpl_ProcessVertices,
8046 /*** State block ***/
8047 IWineD3DDeviceImpl_BeginStateBlock,
8048 IWineD3DDeviceImpl_EndStateBlock,
8049 /*** Scene management ***/
8050 IWineD3DDeviceImpl_BeginScene,
8051 IWineD3DDeviceImpl_EndScene,
8052 IWineD3DDeviceImpl_Present,
8053 IWineD3DDeviceImpl_Clear,
8054 IWineD3DDeviceImpl_ClearRendertargetView,
8055 /*** Drawing ***/
8056 IWineD3DDeviceImpl_SetPrimitiveType,
8057 IWineD3DDeviceImpl_GetPrimitiveType,
8058 IWineD3DDeviceImpl_DrawPrimitive,
8059 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8060 IWineD3DDeviceImpl_DrawPrimitiveUP,
8061 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8062 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8063 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8064 IWineD3DDeviceImpl_DrawRectPatch,
8065 IWineD3DDeviceImpl_DrawTriPatch,
8066 IWineD3DDeviceImpl_DeletePatch,
8067 IWineD3DDeviceImpl_ColorFill,
8068 IWineD3DDeviceImpl_UpdateTexture,
8069 IWineD3DDeviceImpl_UpdateSurface,
8070 IWineD3DDeviceImpl_GetFrontBufferData,
8071 /*** object tracking ***/
8072 IWineD3DDeviceImpl_EnumResources
8075 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8076 WINED3DRS_ALPHABLENDENABLE ,
8077 WINED3DRS_ALPHAFUNC ,
8078 WINED3DRS_ALPHAREF ,
8079 WINED3DRS_ALPHATESTENABLE ,
8080 WINED3DRS_BLENDOP ,
8081 WINED3DRS_COLORWRITEENABLE ,
8082 WINED3DRS_DESTBLEND ,
8083 WINED3DRS_DITHERENABLE ,
8084 WINED3DRS_FILLMODE ,
8085 WINED3DRS_FOGDENSITY ,
8086 WINED3DRS_FOGEND ,
8087 WINED3DRS_FOGSTART ,
8088 WINED3DRS_LASTPIXEL ,
8089 WINED3DRS_SHADEMODE ,
8090 WINED3DRS_SRCBLEND ,
8091 WINED3DRS_STENCILENABLE ,
8092 WINED3DRS_STENCILFAIL ,
8093 WINED3DRS_STENCILFUNC ,
8094 WINED3DRS_STENCILMASK ,
8095 WINED3DRS_STENCILPASS ,
8096 WINED3DRS_STENCILREF ,
8097 WINED3DRS_STENCILWRITEMASK ,
8098 WINED3DRS_STENCILZFAIL ,
8099 WINED3DRS_TEXTUREFACTOR ,
8100 WINED3DRS_WRAP0 ,
8101 WINED3DRS_WRAP1 ,
8102 WINED3DRS_WRAP2 ,
8103 WINED3DRS_WRAP3 ,
8104 WINED3DRS_WRAP4 ,
8105 WINED3DRS_WRAP5 ,
8106 WINED3DRS_WRAP6 ,
8107 WINED3DRS_WRAP7 ,
8108 WINED3DRS_ZENABLE ,
8109 WINED3DRS_ZFUNC ,
8110 WINED3DRS_ZWRITEENABLE
8113 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8114 WINED3DTSS_ALPHAARG0 ,
8115 WINED3DTSS_ALPHAARG1 ,
8116 WINED3DTSS_ALPHAARG2 ,
8117 WINED3DTSS_ALPHAOP ,
8118 WINED3DTSS_BUMPENVLOFFSET ,
8119 WINED3DTSS_BUMPENVLSCALE ,
8120 WINED3DTSS_BUMPENVMAT00 ,
8121 WINED3DTSS_BUMPENVMAT01 ,
8122 WINED3DTSS_BUMPENVMAT10 ,
8123 WINED3DTSS_BUMPENVMAT11 ,
8124 WINED3DTSS_COLORARG0 ,
8125 WINED3DTSS_COLORARG1 ,
8126 WINED3DTSS_COLORARG2 ,
8127 WINED3DTSS_COLOROP ,
8128 WINED3DTSS_RESULTARG ,
8129 WINED3DTSS_TEXCOORDINDEX ,
8130 WINED3DTSS_TEXTURETRANSFORMFLAGS
8133 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8134 WINED3DSAMP_ADDRESSU ,
8135 WINED3DSAMP_ADDRESSV ,
8136 WINED3DSAMP_ADDRESSW ,
8137 WINED3DSAMP_BORDERCOLOR ,
8138 WINED3DSAMP_MAGFILTER ,
8139 WINED3DSAMP_MINFILTER ,
8140 WINED3DSAMP_MIPFILTER ,
8141 WINED3DSAMP_MIPMAPLODBIAS ,
8142 WINED3DSAMP_MAXMIPLEVEL ,
8143 WINED3DSAMP_MAXANISOTROPY ,
8144 WINED3DSAMP_SRGBTEXTURE ,
8145 WINED3DSAMP_ELEMENTINDEX
8148 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8149 WINED3DRS_AMBIENT ,
8150 WINED3DRS_AMBIENTMATERIALSOURCE ,
8151 WINED3DRS_CLIPPING ,
8152 WINED3DRS_CLIPPLANEENABLE ,
8153 WINED3DRS_COLORVERTEX ,
8154 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8155 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8156 WINED3DRS_FOGDENSITY ,
8157 WINED3DRS_FOGEND ,
8158 WINED3DRS_FOGSTART ,
8159 WINED3DRS_FOGTABLEMODE ,
8160 WINED3DRS_FOGVERTEXMODE ,
8161 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8162 WINED3DRS_LIGHTING ,
8163 WINED3DRS_LOCALVIEWER ,
8164 WINED3DRS_MULTISAMPLEANTIALIAS ,
8165 WINED3DRS_MULTISAMPLEMASK ,
8166 WINED3DRS_NORMALIZENORMALS ,
8167 WINED3DRS_PATCHEDGESTYLE ,
8168 WINED3DRS_POINTSCALE_A ,
8169 WINED3DRS_POINTSCALE_B ,
8170 WINED3DRS_POINTSCALE_C ,
8171 WINED3DRS_POINTSCALEENABLE ,
8172 WINED3DRS_POINTSIZE ,
8173 WINED3DRS_POINTSIZE_MAX ,
8174 WINED3DRS_POINTSIZE_MIN ,
8175 WINED3DRS_POINTSPRITEENABLE ,
8176 WINED3DRS_RANGEFOGENABLE ,
8177 WINED3DRS_SPECULARMATERIALSOURCE ,
8178 WINED3DRS_TWEENFACTOR ,
8179 WINED3DRS_VERTEXBLEND ,
8180 WINED3DRS_CULLMODE ,
8181 WINED3DRS_FOGCOLOR
8184 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8185 WINED3DTSS_TEXCOORDINDEX ,
8186 WINED3DTSS_TEXTURETRANSFORMFLAGS
8189 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8190 WINED3DSAMP_DMAPOFFSET
8193 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8194 DWORD rep = This->StateTable[state].representative;
8195 DWORD idx;
8196 BYTE shift;
8197 UINT i;
8198 WineD3DContext *context;
8200 if(!rep) return;
8201 for(i = 0; i < This->numContexts; i++) {
8202 context = This->contexts[i];
8203 if(isStateDirty(context, rep)) continue;
8205 context->dirtyArray[context->numDirtyEntries++] = rep;
8206 idx = rep >> 5;
8207 shift = rep & 0x1f;
8208 context->isStateDirty[idx] |= (1 << shift);
8212 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8213 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8214 /* The drawable size of a pbuffer render target is the current pbuffer size
8216 *width = dev->pbufferWidth;
8217 *height = dev->pbufferHeight;
8220 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8221 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8223 *width = This->pow2Width;
8224 *height = This->pow2Height;
8227 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8228 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8229 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8230 * current context's drawable, which is the size of the back buffer of the swapchain
8231 * the active context belongs to. The back buffer of the swapchain is stored as the
8232 * surface the context belongs to.
8234 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8235 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;